Commit | Line | Data |
---|---|---|
2796a01c AL |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | // | |
3 | // AWINIC AW37503 Regulator Driver | |
4 | // | |
5 | // Copyright (C) 2023 awinic. All Rights Reserved | |
6 | // | |
7 | // Author: <like@awinic.com> | |
8 | ||
9 | #include <linux/err.h> | |
10 | #include <linux/gpio/consumer.h> | |
11 | #include <linux/i2c.h> | |
12 | #include <linux/module.h> | |
13 | #include <linux/regmap.h> | |
14 | #include <linux/regulator/driver.h> | |
15 | #include <linux/regulator/machine.h> | |
16 | ||
17 | #define AW37503_REG_VPOS 0x00 | |
18 | #define AW37503_REG_VNEG 0x01 | |
19 | #define AW37503_REG_APPS 0x03 | |
20 | #define AW37503_REG_CONTROL 0x04 | |
21 | #define AW37503_REG_WPRTEN 0x21 | |
22 | ||
23 | #define AW37503_VOUT_MASK 0x1F | |
24 | #define AW37503_VOUT_N_VOLTAGE 0x15 | |
25 | #define AW37503_VOUT_VMIN 4000000 | |
26 | #define AW37503_VOUT_VMAX 6000000 | |
27 | #define AW37503_VOUT_STEP 100000 | |
28 | ||
29 | #define AW37503_REG_APPS_DIS_VPOS BIT(1) | |
30 | #define AW37503_REG_APPS_DIS_VNEG BIT(0) | |
31 | ||
32 | #define AW37503_REGULATOR_ID_VPOS 0 | |
33 | #define AW37503_REGULATOR_ID_VNEG 1 | |
34 | #define AW37503_MAX_REGULATORS 2 | |
35 | ||
36 | struct aw37503_reg_pdata { | |
37 | struct gpio_desc *en_gpiod; | |
38 | int ena_gpio_state; | |
39 | }; | |
40 | ||
41 | struct aw37503_regulator { | |
42 | struct device *dev; | |
43 | struct aw37503_reg_pdata reg_pdata[AW37503_MAX_REGULATORS]; | |
44 | }; | |
45 | ||
46 | static int aw37503_regulator_enable(struct regulator_dev *rdev) | |
47 | { | |
48 | struct aw37503_regulator *chip = rdev_get_drvdata(rdev); | |
49 | int id = rdev_get_id(rdev); | |
50 | struct aw37503_reg_pdata *rpdata = &chip->reg_pdata[id]; | |
51 | int ret; | |
52 | ||
53 | if (!IS_ERR(rpdata->en_gpiod)) { | |
54 | gpiod_set_value_cansleep(rpdata->en_gpiod, 1); | |
55 | rpdata->ena_gpio_state = 1; | |
56 | } | |
57 | ||
58 | /* Hardware automatically enable discharge bit in enable */ | |
59 | if (rdev->constraints->active_discharge == | |
60 | REGULATOR_ACTIVE_DISCHARGE_DISABLE) { | |
61 | ret = regulator_set_active_discharge_regmap(rdev, false); | |
62 | if (ret < 0) { | |
63 | dev_err(chip->dev, "Failed to disable active discharge: %d\n", | |
64 | ret); | |
65 | return ret; | |
66 | } | |
67 | } | |
68 | ||
69 | return 0; | |
70 | } | |
71 | ||
72 | static int aw37503_regulator_disable(struct regulator_dev *rdev) | |
73 | { | |
74 | struct aw37503_regulator *chip = rdev_get_drvdata(rdev); | |
75 | int id = rdev_get_id(rdev); | |
76 | struct aw37503_reg_pdata *rpdata = &chip->reg_pdata[id]; | |
77 | ||
78 | if (!IS_ERR(rpdata->en_gpiod)) { | |
79 | gpiod_set_value_cansleep(rpdata->en_gpiod, 0); | |
80 | rpdata->ena_gpio_state = 0; | |
81 | } | |
82 | ||
83 | return 0; | |
84 | } | |
85 | ||
86 | static int aw37503_regulator_is_enabled(struct regulator_dev *rdev) | |
87 | { | |
88 | struct aw37503_regulator *chip = rdev_get_drvdata(rdev); | |
89 | int id = rdev_get_id(rdev); | |
90 | struct aw37503_reg_pdata *rpdata = &chip->reg_pdata[id]; | |
91 | ||
92 | if (!IS_ERR(rpdata->en_gpiod)) | |
93 | return rpdata->ena_gpio_state; | |
94 | ||
95 | return 1; | |
96 | } | |
97 | ||
98 | static const struct regulator_ops aw37503_regulator_ops = { | |
99 | .enable = aw37503_regulator_enable, | |
100 | .disable = aw37503_regulator_disable, | |
101 | .is_enabled = aw37503_regulator_is_enabled, | |
102 | .list_voltage = regulator_list_voltage_linear, | |
103 | .map_voltage = regulator_map_voltage_linear, | |
104 | .get_voltage_sel = regulator_get_voltage_sel_regmap, | |
105 | .set_voltage_sel = regulator_set_voltage_sel_regmap, | |
106 | .set_active_discharge = regulator_set_active_discharge_regmap, | |
107 | }; | |
108 | ||
109 | static int aw37503_of_parse_cb(struct device_node *np, | |
110 | const struct regulator_desc *desc, | |
111 | struct regulator_config *config) | |
112 | { | |
113 | struct aw37503_regulator *chip = config->driver_data; | |
114 | struct aw37503_reg_pdata *rpdata = &chip->reg_pdata[desc->id]; | |
115 | int ret; | |
116 | ||
117 | rpdata->en_gpiod = devm_fwnode_gpiod_get(chip->dev, of_fwnode_handle(np), | |
118 | "enable", GPIOD_OUT_LOW, | |
119 | "enable"); | |
120 | ||
121 | if (IS_ERR(rpdata->en_gpiod)) { | |
122 | ret = PTR_ERR(rpdata->en_gpiod); | |
123 | ||
124 | /* Ignore the error other than probe defer */ | |
125 | if (ret == -EPROBE_DEFER) | |
126 | return ret; | |
127 | return 0; | |
128 | } | |
129 | ||
130 | return 0; | |
131 | } | |
132 | ||
133 | #define AW37503_REGULATOR_DESC(_id, _name) \ | |
134 | [AW37503_REGULATOR_ID_##_id] = { \ | |
135 | .name = "aw37503-"#_name, \ | |
136 | .supply_name = "vin", \ | |
137 | .id = AW37503_REGULATOR_ID_##_id, \ | |
138 | .of_match = of_match_ptr(#_name), \ | |
139 | .of_parse_cb = aw37503_of_parse_cb, \ | |
140 | .ops = &aw37503_regulator_ops, \ | |
141 | .n_voltages = AW37503_VOUT_N_VOLTAGE, \ | |
142 | .min_uV = AW37503_VOUT_VMIN, \ | |
143 | .uV_step = AW37503_VOUT_STEP, \ | |
144 | .enable_time = 500, \ | |
145 | .vsel_mask = AW37503_VOUT_MASK, \ | |
146 | .vsel_reg = AW37503_REG_##_id, \ | |
147 | .active_discharge_off = 0, \ | |
148 | .active_discharge_on = AW37503_REG_APPS_DIS_##_id, \ | |
149 | .active_discharge_mask = AW37503_REG_APPS_DIS_##_id, \ | |
150 | .active_discharge_reg = AW37503_REG_APPS, \ | |
151 | .type = REGULATOR_VOLTAGE, \ | |
152 | .owner = THIS_MODULE, \ | |
153 | } | |
154 | ||
155 | static const struct regulator_desc aw_regs_desc[AW37503_MAX_REGULATORS] = { | |
156 | AW37503_REGULATOR_DESC(VPOS, outp), | |
157 | AW37503_REGULATOR_DESC(VNEG, outn), | |
158 | }; | |
159 | ||
160 | static const struct regmap_range aw37503_no_reg_ranges[] = { | |
161 | regmap_reg_range(AW37503_REG_CONTROL + 1, | |
162 | AW37503_REG_WPRTEN - 1), | |
163 | }; | |
164 | ||
165 | static const struct regmap_access_table aw37503_no_reg_table = { | |
166 | .no_ranges = aw37503_no_reg_ranges, | |
167 | .n_no_ranges = ARRAY_SIZE(aw37503_no_reg_ranges), | |
168 | }; | |
169 | ||
170 | static const struct regmap_config aw37503_regmap_config = { | |
171 | .reg_bits = 8, | |
172 | .val_bits = 8, | |
173 | .max_register = AW37503_REG_WPRTEN, | |
174 | .rd_table = &aw37503_no_reg_table, | |
175 | .wr_table = &aw37503_no_reg_table, | |
176 | }; | |
177 | ||
178 | static int aw37503_probe(struct i2c_client *client) | |
179 | { | |
180 | struct device *dev = &client->dev; | |
181 | struct aw37503_regulator *chip; | |
182 | struct regulator_dev *rdev; | |
183 | struct regmap *regmap; | |
184 | struct regulator_config config = { }; | |
185 | int id; | |
186 | ||
187 | chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL); | |
188 | if (!chip) | |
189 | return -ENOMEM; | |
190 | ||
191 | regmap = devm_regmap_init_i2c(client, &aw37503_regmap_config); | |
192 | if (IS_ERR(regmap)) | |
193 | return dev_err_probe(dev, PTR_ERR(regmap), | |
194 | "Failed to init regmap\n"); | |
195 | ||
196 | i2c_set_clientdata(client, chip); | |
197 | chip->dev = dev; | |
198 | ||
199 | config.regmap = regmap; | |
200 | config.dev = dev; | |
201 | config.driver_data = chip; | |
202 | ||
203 | for (id = 0; id < AW37503_MAX_REGULATORS; ++id) { | |
204 | rdev = devm_regulator_register(dev, &aw_regs_desc[id], | |
205 | &config); | |
206 | if (IS_ERR(rdev)) | |
207 | return dev_err_probe(dev, PTR_ERR(rdev), | |
208 | "Failed to register regulator %s\n", | |
209 | aw_regs_desc[id].name); | |
210 | } | |
211 | return 0; | |
212 | } | |
213 | ||
214 | static const struct i2c_device_id aw37503_id[] = { | |
215 | {.name = "aw37503",}, | |
216 | {}, | |
217 | }; | |
218 | MODULE_DEVICE_TABLE(i2c, aw37503_id); | |
219 | ||
220 | static const struct of_device_id aw37503_of_match[] = { | |
221 | {.compatible = "awinic,aw37503",}, | |
222 | { /* Sentinel */ }, | |
223 | }; | |
224 | ||
225 | MODULE_DEVICE_TABLE(of, aw37503_of_match); | |
226 | ||
227 | static struct i2c_driver aw37503_i2c_driver = { | |
228 | .driver = { | |
229 | .name = "aw37503", | |
230 | .of_match_table = aw37503_of_match, | |
231 | }, | |
21cc7f81 | 232 | .probe = aw37503_probe, |
2796a01c AL |
233 | .id_table = aw37503_id, |
234 | }; | |
235 | ||
236 | module_i2c_driver(aw37503_i2c_driver); | |
237 | ||
238 | MODULE_DESCRIPTION("aw37503 regulator driver"); | |
239 | MODULE_AUTHOR("Alec Li <like@awinic.com>"); | |
240 | MODULE_LICENSE("GPL"); |