Commit | Line | Data |
---|---|---|
a265b03b AM |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | #include <linux/module.h> | |
3 | #include <linux/i2c.h> | |
4 | #include <linux/of.h> | |
5 | #include <linux/regulator/driver.h> | |
6 | #include <linux/regmap.h> | |
7 | ||
8 | static const struct regulator_ops pg86x_ops = { | |
9 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | |
10 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
11 | .list_voltage = regulator_list_voltage_linear_range, | |
12 | }; | |
13 | ||
14 | static const struct regulator_linear_range pg86x_buck1_ranges[] = { | |
15 | REGULATOR_LINEAR_RANGE( 0, 0, 10, 0), | |
16 | REGULATOR_LINEAR_RANGE(1000000, 11, 34, 25000), | |
17 | REGULATOR_LINEAR_RANGE(1600000, 35, 47, 50000), | |
18 | }; | |
19 | ||
20 | static const struct regulator_linear_range pg86x_buck2_ranges[] = { | |
21 | REGULATOR_LINEAR_RANGE( 0, 0, 15, 0), | |
22 | REGULATOR_LINEAR_RANGE(1000000, 16, 39, 25000), | |
23 | REGULATOR_LINEAR_RANGE(1600000, 40, 52, 50000), | |
24 | }; | |
25 | ||
26 | static const struct regulator_desc pg86x_regulators[] = { | |
27 | { | |
28 | .id = 0, | |
29 | .type = REGULATOR_VOLTAGE, | |
30 | .name = "buck1", | |
31 | .of_match = of_match_ptr("buck1"), | |
32 | .n_voltages = 11 + 24 + 13, | |
33 | .linear_ranges = pg86x_buck1_ranges, | |
34 | .n_linear_ranges = 3, | |
35 | .vsel_reg = 0x24, | |
36 | .vsel_mask = 0xff, | |
37 | .ops = &pg86x_ops, | |
38 | .owner = THIS_MODULE | |
39 | }, | |
40 | { | |
41 | .id = 1, | |
42 | .type = REGULATOR_VOLTAGE, | |
43 | .name = "buck2", | |
44 | .of_match = of_match_ptr("buck2"), | |
45 | .n_voltages = 16 + 24 + 13, | |
46 | .linear_ranges = pg86x_buck2_ranges, | |
47 | .n_linear_ranges = 3, | |
48 | .vsel_reg = 0x13, | |
49 | .vsel_mask = 0xff, | |
50 | .ops = &pg86x_ops, | |
51 | .owner = THIS_MODULE | |
52 | }, | |
53 | }; | |
54 | ||
55 | static const struct regmap_config pg86x_regmap = { | |
56 | .reg_bits = 8, | |
57 | .val_bits = 8, | |
58 | }; | |
59 | ||
60 | static int pg86x_i2c_probe(struct i2c_client *i2c) | |
61 | { | |
62 | int id, ret; | |
63 | struct regulator_config config = {.dev = &i2c->dev}; | |
64 | struct regmap *regmap = devm_regmap_init_i2c(i2c, &pg86x_regmap); | |
65 | ||
66 | if (IS_ERR(regmap)) { | |
67 | ret = PTR_ERR(regmap); | |
68 | dev_err(&i2c->dev, "regmap init failed: %d\n", ret); | |
69 | return ret; | |
70 | } | |
71 | ||
72 | for (id = 0; id < ARRAY_SIZE(pg86x_regulators); id++) { | |
73 | struct regulator_dev *rdev; | |
74 | rdev = devm_regulator_register(&i2c->dev, | |
75 | &pg86x_regulators[id], | |
76 | &config); | |
77 | if (IS_ERR(rdev)) { | |
78 | ret = PTR_ERR(rdev); | |
79 | dev_err(&i2c->dev, "failed to register %s: %d\n", | |
80 | pg86x_regulators[id].name, ret); | |
81 | return ret; | |
82 | } | |
83 | } | |
84 | return 0; | |
85 | } | |
86 | ||
87 | static const struct of_device_id pg86x_dt_ids [] = { | |
88 | { .compatible = "marvell,88pg867" }, | |
89 | { .compatible = "marvell,88pg868" }, | |
90 | { } | |
91 | }; | |
92 | MODULE_DEVICE_TABLE(of, pg86x_dt_ids); | |
93 | ||
94 | static const struct i2c_device_id pg86x_i2c_id[] = { | |
95 | { "88pg867", }, | |
96 | { "88pg868", }, | |
97 | { } | |
98 | }; | |
99 | MODULE_DEVICE_TABLE(i2c, pg86x_i2c_id); | |
100 | ||
101 | static struct i2c_driver pg86x_regulator_driver = { | |
102 | .driver = { | |
103 | .name = "88pg86x", | |
104 | .of_match_table = of_match_ptr(pg86x_dt_ids), | |
105 | }, | |
106 | .probe_new = pg86x_i2c_probe, | |
107 | .id_table = pg86x_i2c_id, | |
108 | }; | |
109 | ||
110 | module_i2c_driver(pg86x_regulator_driver); | |
111 | ||
112 | MODULE_DESCRIPTION("Marvell 88PG86X voltage regulator"); | |
113 | MODULE_AUTHOR("Alexander Monakov <amonakov@gmail.com>"); | |
114 | MODULE_LICENSE("GPL"); |