1 | // SPDX-License-Identifier: GPL-2.0-or-later |
2 | /* |
3 | * DA9150 Core MFD Driver |
4 | * |
5 | * Copyright (c) 2014 Dialog Semiconductor |
6 | * |
7 | * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com> |
8 | */ |
9 | |
10 | #include <linux/kernel.h> |
11 | #include <linux/module.h> |
12 | #include <linux/platform_device.h> |
13 | #include <linux/i2c.h> |
14 | #include <linux/regmap.h> |
15 | #include <linux/slab.h> |
16 | #include <linux/irq.h> |
17 | #include <linux/interrupt.h> |
18 | #include <linux/mfd/core.h> |
19 | #include <linux/mfd/da9150/core.h> |
20 | #include <linux/mfd/da9150/registers.h> |
21 | |
22 | /* Raw device access, used for QIF */ |
23 | static int da9150_i2c_read_device(struct i2c_client *client, u8 addr, int count, |
24 | u8 *buf) |
25 | { |
26 | struct i2c_msg xfer; |
27 | int ret; |
28 | |
29 | /* |
30 | * Read is split into two transfers as device expects STOP/START rather |
31 | * than repeated start to carry out this kind of access. |
32 | */ |
33 | |
34 | /* Write address */ |
35 | xfer.addr = client->addr; |
36 | xfer.flags = 0; |
37 | xfer.len = 1; |
38 | xfer.buf = &addr; |
39 | |
40 | ret = i2c_transfer(adap: client->adapter, msgs: &xfer, num: 1); |
41 | if (ret != 1) { |
42 | if (ret < 0) |
43 | return ret; |
44 | else |
45 | return -EIO; |
46 | } |
47 | |
48 | /* Read data */ |
49 | xfer.addr = client->addr; |
50 | xfer.flags = I2C_M_RD; |
51 | xfer.len = count; |
52 | xfer.buf = buf; |
53 | |
54 | ret = i2c_transfer(adap: client->adapter, msgs: &xfer, num: 1); |
55 | if (ret == 1) |
56 | return 0; |
57 | else if (ret < 0) |
58 | return ret; |
59 | else |
60 | return -EIO; |
61 | } |
62 | |
63 | static int da9150_i2c_write_device(struct i2c_client *client, u8 addr, |
64 | int count, const u8 *buf) |
65 | { |
66 | struct i2c_msg xfer; |
67 | u8 *reg_data; |
68 | int ret; |
69 | |
70 | reg_data = kzalloc(size: 1 + count, GFP_KERNEL); |
71 | if (!reg_data) |
72 | return -ENOMEM; |
73 | |
74 | reg_data[0] = addr; |
75 | memcpy(®_data[1], buf, count); |
76 | |
77 | /* Write address & data */ |
78 | xfer.addr = client->addr; |
79 | xfer.flags = 0; |
80 | xfer.len = 1 + count; |
81 | xfer.buf = reg_data; |
82 | |
83 | ret = i2c_transfer(adap: client->adapter, msgs: &xfer, num: 1); |
84 | kfree(objp: reg_data); |
85 | if (ret == 1) |
86 | return 0; |
87 | else if (ret < 0) |
88 | return ret; |
89 | else |
90 | return -EIO; |
91 | } |
92 | |
93 | static bool da9150_volatile_reg(struct device *dev, unsigned int reg) |
94 | { |
95 | switch (reg) { |
96 | case DA9150_PAGE_CON: |
97 | case DA9150_STATUS_A: |
98 | case DA9150_STATUS_B: |
99 | case DA9150_STATUS_C: |
100 | case DA9150_STATUS_D: |
101 | case DA9150_STATUS_E: |
102 | case DA9150_STATUS_F: |
103 | case DA9150_STATUS_G: |
104 | case DA9150_STATUS_H: |
105 | case DA9150_STATUS_I: |
106 | case DA9150_STATUS_J: |
107 | case DA9150_STATUS_K: |
108 | case DA9150_STATUS_L: |
109 | case DA9150_STATUS_N: |
110 | case DA9150_FAULT_LOG_A: |
111 | case DA9150_FAULT_LOG_B: |
112 | case DA9150_EVENT_E: |
113 | case DA9150_EVENT_F: |
114 | case DA9150_EVENT_G: |
115 | case DA9150_EVENT_H: |
116 | case DA9150_CONTROL_B: |
117 | case DA9150_CONTROL_C: |
118 | case DA9150_GPADC_MAN: |
119 | case DA9150_GPADC_RES_A: |
120 | case DA9150_GPADC_RES_B: |
121 | case DA9150_ADETVB_CFG_C: |
122 | case DA9150_ADETD_STAT: |
123 | case DA9150_ADET_CMPSTAT: |
124 | case DA9150_ADET_CTRL_A: |
125 | case DA9150_PPR_TCTR_B: |
126 | case DA9150_COREBTLD_STAT_A: |
127 | case DA9150_CORE_DATA_A: |
128 | case DA9150_CORE_DATA_B: |
129 | case DA9150_CORE_DATA_C: |
130 | case DA9150_CORE_DATA_D: |
131 | case DA9150_CORE2WIRE_STAT_A: |
132 | case DA9150_FW_CTRL_C: |
133 | case DA9150_FG_CTRL_B: |
134 | case DA9150_FW_CTRL_B: |
135 | case DA9150_GPADC_CMAN: |
136 | case DA9150_GPADC_CRES_A: |
137 | case DA9150_GPADC_CRES_B: |
138 | case DA9150_CC_ICHG_RES_A: |
139 | case DA9150_CC_ICHG_RES_B: |
140 | case DA9150_CC_IAVG_RES_A: |
141 | case DA9150_CC_IAVG_RES_B: |
142 | case DA9150_TAUX_CTRL_A: |
143 | case DA9150_TAUX_VALUE_H: |
144 | case DA9150_TAUX_VALUE_L: |
145 | case DA9150_TBAT_RES_A: |
146 | case DA9150_TBAT_RES_B: |
147 | return true; |
148 | default: |
149 | return false; |
150 | } |
151 | } |
152 | |
153 | static const struct regmap_range_cfg da9150_range_cfg[] = { |
154 | { |
155 | .range_min = DA9150_PAGE_CON, |
156 | .range_max = DA9150_TBAT_RES_B, |
157 | .selector_reg = DA9150_PAGE_CON, |
158 | .selector_mask = DA9150_I2C_PAGE_MASK, |
159 | .selector_shift = DA9150_I2C_PAGE_SHIFT, |
160 | .window_start = 0, |
161 | .window_len = 256, |
162 | }, |
163 | }; |
164 | |
165 | static const struct regmap_config da9150_regmap_config = { |
166 | .reg_bits = 8, |
167 | .val_bits = 8, |
168 | .ranges = da9150_range_cfg, |
169 | .num_ranges = ARRAY_SIZE(da9150_range_cfg), |
170 | .max_register = DA9150_TBAT_RES_B, |
171 | |
172 | .cache_type = REGCACHE_RBTREE, |
173 | |
174 | .volatile_reg = da9150_volatile_reg, |
175 | }; |
176 | |
177 | void da9150_read_qif(struct da9150 *da9150, u8 addr, int count, u8 *buf) |
178 | { |
179 | int ret; |
180 | |
181 | ret = da9150_i2c_read_device(client: da9150->core_qif, addr, count, buf); |
182 | if (ret < 0) |
183 | dev_err(da9150->dev, "Failed to read from QIF 0x%x: %d\n" , |
184 | addr, ret); |
185 | } |
186 | EXPORT_SYMBOL_GPL(da9150_read_qif); |
187 | |
188 | void da9150_write_qif(struct da9150 *da9150, u8 addr, int count, const u8 *buf) |
189 | { |
190 | int ret; |
191 | |
192 | ret = da9150_i2c_write_device(client: da9150->core_qif, addr, count, buf); |
193 | if (ret < 0) |
194 | dev_err(da9150->dev, "Failed to write to QIF 0x%x: %d\n" , |
195 | addr, ret); |
196 | } |
197 | EXPORT_SYMBOL_GPL(da9150_write_qif); |
198 | |
199 | u8 da9150_reg_read(struct da9150 *da9150, u16 reg) |
200 | { |
201 | int val, ret; |
202 | |
203 | ret = regmap_read(map: da9150->regmap, reg, val: &val); |
204 | if (ret) |
205 | dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n" , |
206 | reg, ret); |
207 | |
208 | return (u8) val; |
209 | } |
210 | EXPORT_SYMBOL_GPL(da9150_reg_read); |
211 | |
212 | void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val) |
213 | { |
214 | int ret; |
215 | |
216 | ret = regmap_write(map: da9150->regmap, reg, val); |
217 | if (ret) |
218 | dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n" , |
219 | reg, ret); |
220 | } |
221 | EXPORT_SYMBOL_GPL(da9150_reg_write); |
222 | |
223 | void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val) |
224 | { |
225 | int ret; |
226 | |
227 | ret = regmap_update_bits(map: da9150->regmap, reg, mask, val); |
228 | if (ret) |
229 | dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n" , |
230 | reg, ret); |
231 | } |
232 | EXPORT_SYMBOL_GPL(da9150_set_bits); |
233 | |
234 | void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf) |
235 | { |
236 | int ret; |
237 | |
238 | ret = regmap_bulk_read(map: da9150->regmap, reg, val: buf, val_count: count); |
239 | if (ret) |
240 | dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n" , |
241 | reg, ret); |
242 | } |
243 | EXPORT_SYMBOL_GPL(da9150_bulk_read); |
244 | |
245 | void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf) |
246 | { |
247 | int ret; |
248 | |
249 | ret = regmap_raw_write(map: da9150->regmap, reg, val: buf, val_len: count); |
250 | if (ret) |
251 | dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n" , |
252 | reg, ret); |
253 | } |
254 | EXPORT_SYMBOL_GPL(da9150_bulk_write); |
255 | |
256 | static const struct regmap_irq da9150_irqs[] = { |
257 | [DA9150_IRQ_VBUS] = { |
258 | .reg_offset = 0, |
259 | .mask = DA9150_E_VBUS_MASK, |
260 | }, |
261 | [DA9150_IRQ_CHG] = { |
262 | .reg_offset = 0, |
263 | .mask = DA9150_E_CHG_MASK, |
264 | }, |
265 | [DA9150_IRQ_TCLASS] = { |
266 | .reg_offset = 0, |
267 | .mask = DA9150_E_TCLASS_MASK, |
268 | }, |
269 | [DA9150_IRQ_TJUNC] = { |
270 | .reg_offset = 0, |
271 | .mask = DA9150_E_TJUNC_MASK, |
272 | }, |
273 | [DA9150_IRQ_VFAULT] = { |
274 | .reg_offset = 0, |
275 | .mask = DA9150_E_VFAULT_MASK, |
276 | }, |
277 | [DA9150_IRQ_CONF] = { |
278 | .reg_offset = 1, |
279 | .mask = DA9150_E_CONF_MASK, |
280 | }, |
281 | [DA9150_IRQ_DAT] = { |
282 | .reg_offset = 1, |
283 | .mask = DA9150_E_DAT_MASK, |
284 | }, |
285 | [DA9150_IRQ_DTYPE] = { |
286 | .reg_offset = 1, |
287 | .mask = DA9150_E_DTYPE_MASK, |
288 | }, |
289 | [DA9150_IRQ_ID] = { |
290 | .reg_offset = 1, |
291 | .mask = DA9150_E_ID_MASK, |
292 | }, |
293 | [DA9150_IRQ_ADP] = { |
294 | .reg_offset = 1, |
295 | .mask = DA9150_E_ADP_MASK, |
296 | }, |
297 | [DA9150_IRQ_SESS_END] = { |
298 | .reg_offset = 1, |
299 | .mask = DA9150_E_SESS_END_MASK, |
300 | }, |
301 | [DA9150_IRQ_SESS_VLD] = { |
302 | .reg_offset = 1, |
303 | .mask = DA9150_E_SESS_VLD_MASK, |
304 | }, |
305 | [DA9150_IRQ_FG] = { |
306 | .reg_offset = 2, |
307 | .mask = DA9150_E_FG_MASK, |
308 | }, |
309 | [DA9150_IRQ_GP] = { |
310 | .reg_offset = 2, |
311 | .mask = DA9150_E_GP_MASK, |
312 | }, |
313 | [DA9150_IRQ_TBAT] = { |
314 | .reg_offset = 2, |
315 | .mask = DA9150_E_TBAT_MASK, |
316 | }, |
317 | [DA9150_IRQ_GPIOA] = { |
318 | .reg_offset = 2, |
319 | .mask = DA9150_E_GPIOA_MASK, |
320 | }, |
321 | [DA9150_IRQ_GPIOB] = { |
322 | .reg_offset = 2, |
323 | .mask = DA9150_E_GPIOB_MASK, |
324 | }, |
325 | [DA9150_IRQ_GPIOC] = { |
326 | .reg_offset = 2, |
327 | .mask = DA9150_E_GPIOC_MASK, |
328 | }, |
329 | [DA9150_IRQ_GPIOD] = { |
330 | .reg_offset = 2, |
331 | .mask = DA9150_E_GPIOD_MASK, |
332 | }, |
333 | [DA9150_IRQ_GPADC] = { |
334 | .reg_offset = 2, |
335 | .mask = DA9150_E_GPADC_MASK, |
336 | }, |
337 | [DA9150_IRQ_WKUP] = { |
338 | .reg_offset = 3, |
339 | .mask = DA9150_E_WKUP_MASK, |
340 | }, |
341 | }; |
342 | |
343 | static const struct regmap_irq_chip da9150_regmap_irq_chip = { |
344 | .name = "da9150_irq" , |
345 | .status_base = DA9150_EVENT_E, |
346 | .mask_base = DA9150_IRQ_MASK_E, |
347 | .ack_base = DA9150_EVENT_E, |
348 | .num_regs = DA9150_NUM_IRQ_REGS, |
349 | .irqs = da9150_irqs, |
350 | .num_irqs = ARRAY_SIZE(da9150_irqs), |
351 | }; |
352 | |
353 | static const struct resource da9150_gpadc_resources[] = { |
354 | DEFINE_RES_IRQ_NAMED(DA9150_IRQ_GPADC, "GPADC" ), |
355 | }; |
356 | |
357 | static const struct resource da9150_charger_resources[] = { |
358 | DEFINE_RES_IRQ_NAMED(DA9150_IRQ_CHG, "CHG_STATUS" ), |
359 | DEFINE_RES_IRQ_NAMED(DA9150_IRQ_TJUNC, "CHG_TJUNC" ), |
360 | DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VFAULT, "CHG_VFAULT" ), |
361 | DEFINE_RES_IRQ_NAMED(DA9150_IRQ_VBUS, "CHG_VBUS" ), |
362 | }; |
363 | |
364 | static const struct resource da9150_fg_resources[] = { |
365 | DEFINE_RES_IRQ_NAMED(DA9150_IRQ_FG, "FG" ), |
366 | }; |
367 | |
368 | enum da9150_dev_idx { |
369 | DA9150_GPADC_IDX = 0, |
370 | DA9150_CHARGER_IDX, |
371 | DA9150_FG_IDX, |
372 | }; |
373 | |
374 | static struct mfd_cell da9150_devs[] = { |
375 | [DA9150_GPADC_IDX] = { |
376 | .name = "da9150-gpadc" , |
377 | .of_compatible = "dlg,da9150-gpadc" , |
378 | .resources = da9150_gpadc_resources, |
379 | .num_resources = ARRAY_SIZE(da9150_gpadc_resources), |
380 | }, |
381 | [DA9150_CHARGER_IDX] = { |
382 | .name = "da9150-charger" , |
383 | .of_compatible = "dlg,da9150-charger" , |
384 | .resources = da9150_charger_resources, |
385 | .num_resources = ARRAY_SIZE(da9150_charger_resources), |
386 | }, |
387 | [DA9150_FG_IDX] = { |
388 | .name = "da9150-fuel-gauge" , |
389 | .of_compatible = "dlg,da9150-fuel-gauge" , |
390 | .resources = da9150_fg_resources, |
391 | .num_resources = ARRAY_SIZE(da9150_fg_resources), |
392 | }, |
393 | }; |
394 | |
395 | static int da9150_probe(struct i2c_client *client) |
396 | { |
397 | struct da9150 *da9150; |
398 | struct da9150_pdata *pdata = dev_get_platdata(dev: &client->dev); |
399 | int qif_addr; |
400 | int ret; |
401 | |
402 | da9150 = devm_kzalloc(dev: &client->dev, size: sizeof(*da9150), GFP_KERNEL); |
403 | if (!da9150) |
404 | return -ENOMEM; |
405 | |
406 | da9150->dev = &client->dev; |
407 | da9150->irq = client->irq; |
408 | i2c_set_clientdata(client, data: da9150); |
409 | |
410 | da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config); |
411 | if (IS_ERR(ptr: da9150->regmap)) { |
412 | ret = PTR_ERR(ptr: da9150->regmap); |
413 | dev_err(da9150->dev, "Failed to allocate register map: %d\n" , |
414 | ret); |
415 | return ret; |
416 | } |
417 | |
418 | /* Setup secondary I2C interface for QIF access */ |
419 | qif_addr = da9150_reg_read(da9150, DA9150_CORE2WIRE_CTRL_A); |
420 | qif_addr = (qif_addr & DA9150_CORE_BASE_ADDR_MASK) >> 1; |
421 | qif_addr |= DA9150_QIF_I2C_ADDR_LSB; |
422 | da9150->core_qif = i2c_new_dummy_device(adapter: client->adapter, address: qif_addr); |
423 | if (IS_ERR(ptr: da9150->core_qif)) { |
424 | dev_err(da9150->dev, "Failed to attach QIF client\n" ); |
425 | return PTR_ERR(ptr: da9150->core_qif); |
426 | } |
427 | |
428 | i2c_set_clientdata(client: da9150->core_qif, data: da9150); |
429 | |
430 | if (pdata) { |
431 | da9150->irq_base = pdata->irq_base; |
432 | |
433 | da9150_devs[DA9150_FG_IDX].platform_data = pdata->fg_pdata; |
434 | da9150_devs[DA9150_FG_IDX].pdata_size = |
435 | sizeof(struct da9150_fg_pdata); |
436 | } else { |
437 | da9150->irq_base = -1; |
438 | } |
439 | |
440 | ret = regmap_add_irq_chip(map: da9150->regmap, irq: da9150->irq, |
441 | IRQF_TRIGGER_LOW | IRQF_ONESHOT, |
442 | irq_base: da9150->irq_base, chip: &da9150_regmap_irq_chip, |
443 | data: &da9150->regmap_irq_data); |
444 | if (ret) { |
445 | dev_err(da9150->dev, "Failed to add regmap irq chip: %d\n" , |
446 | ret); |
447 | goto regmap_irq_fail; |
448 | } |
449 | |
450 | |
451 | da9150->irq_base = regmap_irq_chip_get_base(data: da9150->regmap_irq_data); |
452 | |
453 | enable_irq_wake(irq: da9150->irq); |
454 | |
455 | ret = mfd_add_devices(parent: da9150->dev, id: -1, cells: da9150_devs, |
456 | ARRAY_SIZE(da9150_devs), NULL, |
457 | irq_base: da9150->irq_base, NULL); |
458 | if (ret) { |
459 | dev_err(da9150->dev, "Failed to add child devices: %d\n" , ret); |
460 | goto mfd_fail; |
461 | } |
462 | |
463 | return 0; |
464 | |
465 | mfd_fail: |
466 | regmap_del_irq_chip(irq: da9150->irq, data: da9150->regmap_irq_data); |
467 | regmap_irq_fail: |
468 | i2c_unregister_device(client: da9150->core_qif); |
469 | |
470 | return ret; |
471 | } |
472 | |
473 | static void da9150_remove(struct i2c_client *client) |
474 | { |
475 | struct da9150 *da9150 = i2c_get_clientdata(client); |
476 | |
477 | regmap_del_irq_chip(irq: da9150->irq, data: da9150->regmap_irq_data); |
478 | mfd_remove_devices(parent: da9150->dev); |
479 | i2c_unregister_device(client: da9150->core_qif); |
480 | } |
481 | |
482 | static void da9150_shutdown(struct i2c_client *client) |
483 | { |
484 | struct da9150 *da9150 = i2c_get_clientdata(client); |
485 | |
486 | /* Make sure we have a wakup source for the device */ |
487 | da9150_set_bits(da9150, DA9150_CONFIG_D, |
488 | DA9150_WKUP_PM_EN_MASK, |
489 | DA9150_WKUP_PM_EN_MASK); |
490 | |
491 | /* Set device to DISABLED mode */ |
492 | da9150_set_bits(da9150, DA9150_CONTROL_C, |
493 | DA9150_DISABLE_MASK, DA9150_DISABLE_MASK); |
494 | } |
495 | |
496 | static const struct i2c_device_id da9150_i2c_id[] = { |
497 | { "da9150" , }, |
498 | { } |
499 | }; |
500 | MODULE_DEVICE_TABLE(i2c, da9150_i2c_id); |
501 | |
502 | static const struct of_device_id da9150_of_match[] = { |
503 | { .compatible = "dlg,da9150" , }, |
504 | { } |
505 | }; |
506 | MODULE_DEVICE_TABLE(of, da9150_of_match); |
507 | |
508 | static struct i2c_driver da9150_driver = { |
509 | .driver = { |
510 | .name = "da9150" , |
511 | .of_match_table = da9150_of_match, |
512 | }, |
513 | .probe = da9150_probe, |
514 | .remove = da9150_remove, |
515 | .shutdown = da9150_shutdown, |
516 | .id_table = da9150_i2c_id, |
517 | }; |
518 | |
519 | module_i2c_driver(da9150_driver); |
520 | |
521 | MODULE_DESCRIPTION("MFD Core Driver for DA9150" ); |
522 | MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>" ); |
523 | MODULE_LICENSE("GPL" ); |
524 | |