1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Driver for TPS65218 Integrated power management chipsets |
4 | * |
5 | * Copyright (C) 2014 Texas Instruments Incorporated - https://www.ti.com/ |
6 | */ |
7 | |
8 | #include <linux/kernel.h> |
9 | #include <linux/device.h> |
10 | #include <linux/module.h> |
11 | #include <linux/platform_device.h> |
12 | #include <linux/init.h> |
13 | #include <linux/i2c.h> |
14 | #include <linux/slab.h> |
15 | #include <linux/regmap.h> |
16 | #include <linux/err.h> |
17 | #include <linux/of.h> |
18 | #include <linux/irq.h> |
19 | #include <linux/interrupt.h> |
20 | #include <linux/mutex.h> |
21 | |
22 | #include <linux/mfd/core.h> |
23 | #include <linux/mfd/tps65218.h> |
24 | |
25 | #define TPS65218_PASSWORD_REGS_UNLOCK 0x7D |
26 | |
27 | static const struct mfd_cell tps65218_cells[] = { |
28 | { |
29 | .name = "tps65218-pwrbutton" , |
30 | .of_compatible = "ti,tps65218-pwrbutton" , |
31 | }, |
32 | { |
33 | .name = "tps65218-gpio" , |
34 | .of_compatible = "ti,tps65218-gpio" , |
35 | }, |
36 | { .name = "tps65218-regulator" , }, |
37 | }; |
38 | |
39 | /** |
40 | * tps65218_reg_write: Write a single tps65218 register. |
41 | * |
42 | * @tps: Device to write to. |
43 | * @reg: Register to write to. |
44 | * @val: Value to write. |
45 | * @level: Password protected level |
46 | */ |
47 | int tps65218_reg_write(struct tps65218 *tps, unsigned int reg, |
48 | unsigned int val, unsigned int level) |
49 | { |
50 | int ret; |
51 | unsigned int xor_reg_val; |
52 | |
53 | switch (level) { |
54 | case TPS65218_PROTECT_NONE: |
55 | return regmap_write(map: tps->regmap, reg, val); |
56 | case TPS65218_PROTECT_L1: |
57 | xor_reg_val = reg ^ TPS65218_PASSWORD_REGS_UNLOCK; |
58 | ret = regmap_write(map: tps->regmap, TPS65218_REG_PASSWORD, |
59 | val: xor_reg_val); |
60 | if (ret < 0) |
61 | return ret; |
62 | |
63 | return regmap_write(map: tps->regmap, reg, val); |
64 | default: |
65 | return -EINVAL; |
66 | } |
67 | } |
68 | EXPORT_SYMBOL_GPL(tps65218_reg_write); |
69 | |
70 | /** |
71 | * tps65218_update_bits: Modify bits w.r.t mask, val and level. |
72 | * |
73 | * @tps: Device to write to. |
74 | * @reg: Register to read-write to. |
75 | * @mask: Mask. |
76 | * @val: Value to write. |
77 | * @level: Password protected level |
78 | */ |
79 | static int tps65218_update_bits(struct tps65218 *tps, unsigned int reg, |
80 | unsigned int mask, unsigned int val, unsigned int level) |
81 | { |
82 | int ret; |
83 | unsigned int data; |
84 | |
85 | ret = regmap_read(map: tps->regmap, reg, val: &data); |
86 | if (ret) { |
87 | dev_err(tps->dev, "Read from reg 0x%x failed\n" , reg); |
88 | return ret; |
89 | } |
90 | |
91 | data &= ~mask; |
92 | data |= val & mask; |
93 | |
94 | mutex_lock(&tps->tps_lock); |
95 | ret = tps65218_reg_write(tps, reg, data, level); |
96 | if (ret) |
97 | dev_err(tps->dev, "Write for reg 0x%x failed\n" , reg); |
98 | mutex_unlock(lock: &tps->tps_lock); |
99 | |
100 | return ret; |
101 | } |
102 | |
103 | int tps65218_set_bits(struct tps65218 *tps, unsigned int reg, |
104 | unsigned int mask, unsigned int val, unsigned int level) |
105 | { |
106 | return tps65218_update_bits(tps, reg, mask, val, level); |
107 | } |
108 | EXPORT_SYMBOL_GPL(tps65218_set_bits); |
109 | |
110 | int tps65218_clear_bits(struct tps65218 *tps, unsigned int reg, |
111 | unsigned int mask, unsigned int level) |
112 | { |
113 | return tps65218_update_bits(tps, reg, mask, val: 0, level); |
114 | } |
115 | EXPORT_SYMBOL_GPL(tps65218_clear_bits); |
116 | |
117 | static const struct regmap_range tps65218_yes_ranges[] = { |
118 | regmap_reg_range(TPS65218_REG_INT1, TPS65218_REG_INT2), |
119 | regmap_reg_range(TPS65218_REG_STATUS, TPS65218_REG_STATUS), |
120 | }; |
121 | |
122 | static const struct regmap_access_table tps65218_volatile_table = { |
123 | .yes_ranges = tps65218_yes_ranges, |
124 | .n_yes_ranges = ARRAY_SIZE(tps65218_yes_ranges), |
125 | }; |
126 | |
127 | static const struct regmap_config tps65218_regmap_config = { |
128 | .reg_bits = 8, |
129 | .val_bits = 8, |
130 | .cache_type = REGCACHE_MAPLE, |
131 | .volatile_table = &tps65218_volatile_table, |
132 | }; |
133 | |
134 | static const struct regmap_irq tps65218_irqs[] = { |
135 | /* INT1 IRQs */ |
136 | [TPS65218_PRGC_IRQ] = { |
137 | .mask = TPS65218_INT1_PRGC, |
138 | }, |
139 | [TPS65218_CC_AQC_IRQ] = { |
140 | .mask = TPS65218_INT1_CC_AQC, |
141 | }, |
142 | [TPS65218_HOT_IRQ] = { |
143 | .mask = TPS65218_INT1_HOT, |
144 | }, |
145 | [TPS65218_PB_IRQ] = { |
146 | .mask = TPS65218_INT1_PB, |
147 | }, |
148 | [TPS65218_AC_IRQ] = { |
149 | .mask = TPS65218_INT1_AC, |
150 | }, |
151 | [TPS65218_VPRG_IRQ] = { |
152 | .mask = TPS65218_INT1_VPRG, |
153 | }, |
154 | [TPS65218_INVALID1_IRQ] = { |
155 | }, |
156 | [TPS65218_INVALID2_IRQ] = { |
157 | }, |
158 | /* INT2 IRQs*/ |
159 | [TPS65218_LS1_I_IRQ] = { |
160 | .mask = TPS65218_INT2_LS1_I, |
161 | .reg_offset = 1, |
162 | }, |
163 | [TPS65218_LS2_I_IRQ] = { |
164 | .mask = TPS65218_INT2_LS2_I, |
165 | .reg_offset = 1, |
166 | }, |
167 | [TPS65218_LS3_I_IRQ] = { |
168 | .mask = TPS65218_INT2_LS3_I, |
169 | .reg_offset = 1, |
170 | }, |
171 | [TPS65218_LS1_F_IRQ] = { |
172 | .mask = TPS65218_INT2_LS1_F, |
173 | .reg_offset = 1, |
174 | }, |
175 | [TPS65218_LS2_F_IRQ] = { |
176 | .mask = TPS65218_INT2_LS2_F, |
177 | .reg_offset = 1, |
178 | }, |
179 | [TPS65218_LS3_F_IRQ] = { |
180 | .mask = TPS65218_INT2_LS3_F, |
181 | .reg_offset = 1, |
182 | }, |
183 | [TPS65218_INVALID3_IRQ] = { |
184 | }, |
185 | [TPS65218_INVALID4_IRQ] = { |
186 | }, |
187 | }; |
188 | |
189 | static struct regmap_irq_chip tps65218_irq_chip = { |
190 | .name = "tps65218" , |
191 | .irqs = tps65218_irqs, |
192 | .num_irqs = ARRAY_SIZE(tps65218_irqs), |
193 | |
194 | .num_regs = 2, |
195 | .mask_base = TPS65218_REG_INT_MASK1, |
196 | .status_base = TPS65218_REG_INT1, |
197 | }; |
198 | |
199 | static const struct of_device_id of_tps65218_match_table[] = { |
200 | { .compatible = "ti,tps65218" , }, |
201 | {} |
202 | }; |
203 | MODULE_DEVICE_TABLE(of, of_tps65218_match_table); |
204 | |
205 | static int tps65218_voltage_set_strict(struct tps65218 *tps) |
206 | { |
207 | u32 strict; |
208 | |
209 | if (of_property_read_u32(np: tps->dev->of_node, |
210 | propname: "ti,strict-supply-voltage-supervision" , |
211 | out_value: &strict)) |
212 | return 0; |
213 | |
214 | if (strict != 0 && strict != 1) { |
215 | dev_err(tps->dev, |
216 | "Invalid ti,strict-supply-voltage-supervision value\n" ); |
217 | return -EINVAL; |
218 | } |
219 | |
220 | tps65218_update_bits(tps, TPS65218_REG_CONFIG1, |
221 | TPS65218_CONFIG1_STRICT, |
222 | val: strict ? TPS65218_CONFIG1_STRICT : 0, |
223 | TPS65218_PROTECT_L1); |
224 | return 0; |
225 | } |
226 | |
227 | static int tps65218_voltage_set_uv_hyst(struct tps65218 *tps) |
228 | { |
229 | u32 hyst; |
230 | |
231 | if (of_property_read_u32(np: tps->dev->of_node, |
232 | propname: "ti,under-voltage-hyst-microvolt" , out_value: &hyst)) |
233 | return 0; |
234 | |
235 | if (hyst != 400000 && hyst != 200000) { |
236 | dev_err(tps->dev, |
237 | "Invalid ti,under-voltage-hyst-microvolt value\n" ); |
238 | return -EINVAL; |
239 | } |
240 | |
241 | tps65218_update_bits(tps, TPS65218_REG_CONFIG2, |
242 | TPS65218_CONFIG2_UVLOHYS, |
243 | val: hyst == 400000 ? TPS65218_CONFIG2_UVLOHYS : 0, |
244 | TPS65218_PROTECT_L1); |
245 | return 0; |
246 | } |
247 | |
248 | static int tps65218_voltage_set_uvlo(struct tps65218 *tps) |
249 | { |
250 | u32 uvlo; |
251 | int uvloval; |
252 | |
253 | if (of_property_read_u32(np: tps->dev->of_node, |
254 | propname: "ti,under-voltage-limit-microvolt" , out_value: &uvlo)) |
255 | return 0; |
256 | |
257 | switch (uvlo) { |
258 | case 2750000: |
259 | uvloval = TPS65218_CONFIG1_UVLO_2750000; |
260 | break; |
261 | case 2950000: |
262 | uvloval = TPS65218_CONFIG1_UVLO_2950000; |
263 | break; |
264 | case 3250000: |
265 | uvloval = TPS65218_CONFIG1_UVLO_3250000; |
266 | break; |
267 | case 3350000: |
268 | uvloval = TPS65218_CONFIG1_UVLO_3350000; |
269 | break; |
270 | default: |
271 | dev_err(tps->dev, |
272 | "Invalid ti,under-voltage-limit-microvolt value\n" ); |
273 | return -EINVAL; |
274 | } |
275 | |
276 | tps65218_update_bits(tps, TPS65218_REG_CONFIG1, |
277 | TPS65218_CONFIG1_UVLO_MASK, val: uvloval, |
278 | TPS65218_PROTECT_L1); |
279 | return 0; |
280 | } |
281 | |
282 | static int tps65218_probe(struct i2c_client *client) |
283 | { |
284 | struct tps65218 *tps; |
285 | int ret; |
286 | unsigned int chipid; |
287 | |
288 | tps = devm_kzalloc(dev: &client->dev, size: sizeof(*tps), GFP_KERNEL); |
289 | if (!tps) |
290 | return -ENOMEM; |
291 | |
292 | i2c_set_clientdata(client, data: tps); |
293 | tps->dev = &client->dev; |
294 | tps->irq = client->irq; |
295 | tps->regmap = devm_regmap_init_i2c(client, &tps65218_regmap_config); |
296 | if (IS_ERR(ptr: tps->regmap)) { |
297 | ret = PTR_ERR(ptr: tps->regmap); |
298 | dev_err(tps->dev, "Failed to allocate register map: %d\n" , |
299 | ret); |
300 | return ret; |
301 | } |
302 | |
303 | mutex_init(&tps->tps_lock); |
304 | |
305 | ret = devm_regmap_add_irq_chip(dev: &client->dev, map: tps->regmap, irq: tps->irq, |
306 | IRQF_ONESHOT, irq_base: 0, chip: &tps65218_irq_chip, |
307 | data: &tps->irq_data); |
308 | if (ret < 0) |
309 | return ret; |
310 | |
311 | ret = regmap_read(map: tps->regmap, TPS65218_REG_CHIPID, val: &chipid); |
312 | if (ret) { |
313 | dev_err(tps->dev, "Failed to read chipid: %d\n" , ret); |
314 | return ret; |
315 | } |
316 | |
317 | tps->rev = chipid & TPS65218_CHIPID_REV_MASK; |
318 | |
319 | ret = tps65218_voltage_set_strict(tps); |
320 | if (ret) |
321 | return ret; |
322 | |
323 | ret = tps65218_voltage_set_uvlo(tps); |
324 | if (ret) |
325 | return ret; |
326 | |
327 | ret = tps65218_voltage_set_uv_hyst(tps); |
328 | if (ret) |
329 | return ret; |
330 | |
331 | ret = mfd_add_devices(parent: tps->dev, PLATFORM_DEVID_AUTO, cells: tps65218_cells, |
332 | ARRAY_SIZE(tps65218_cells), NULL, irq_base: 0, |
333 | irq_domain: regmap_irq_get_domain(data: tps->irq_data)); |
334 | |
335 | return ret; |
336 | } |
337 | |
338 | static const struct i2c_device_id tps65218_id_table[] = { |
339 | { "tps65218" , TPS65218 }, |
340 | { }, |
341 | }; |
342 | MODULE_DEVICE_TABLE(i2c, tps65218_id_table); |
343 | |
344 | static struct i2c_driver tps65218_driver = { |
345 | .driver = { |
346 | .name = "tps65218" , |
347 | .of_match_table = of_tps65218_match_table, |
348 | }, |
349 | .probe = tps65218_probe, |
350 | .id_table = tps65218_id_table, |
351 | }; |
352 | |
353 | module_i2c_driver(tps65218_driver); |
354 | |
355 | MODULE_AUTHOR("J Keerthy <j-keerthy@ti.com>" ); |
356 | MODULE_DESCRIPTION("TPS65218 chip family multi-function driver" ); |
357 | MODULE_LICENSE("GPL v2" ); |
358 | |