da9150-core.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. /*
  2. * DA9150 Core MFD Driver
  3. *
  4. * Copyright (c) 2014 Dialog Semiconductor
  5. *
  6. * Author: Adam Thomson <Adam.Thomson.Opensource@diasemi.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the
  10. * Free Software Foundation; either version 2 of the License, or (at your
  11. * option) any later version.
  12. */
  13. #include <linux/kernel.h>
  14. #include <linux/module.h>
  15. #include <linux/platform_device.h>
  16. #include <linux/i2c.h>
  17. #include <linux/regmap.h>
  18. #include <linux/slab.h>
  19. #include <linux/irq.h>
  20. #include <linux/interrupt.h>
  21. #include <linux/mfd/core.h>
  22. #include <linux/mfd/da9150/core.h>
  23. #include <linux/mfd/da9150/registers.h>
  24. static bool da9150_volatile_reg(struct device *dev, unsigned int reg)
  25. {
  26. switch (reg) {
  27. case DA9150_PAGE_CON:
  28. case DA9150_STATUS_A:
  29. case DA9150_STATUS_B:
  30. case DA9150_STATUS_C:
  31. case DA9150_STATUS_D:
  32. case DA9150_STATUS_E:
  33. case DA9150_STATUS_F:
  34. case DA9150_STATUS_G:
  35. case DA9150_STATUS_H:
  36. case DA9150_STATUS_I:
  37. case DA9150_STATUS_J:
  38. case DA9150_STATUS_K:
  39. case DA9150_STATUS_L:
  40. case DA9150_STATUS_N:
  41. case DA9150_FAULT_LOG_A:
  42. case DA9150_FAULT_LOG_B:
  43. case DA9150_EVENT_E:
  44. case DA9150_EVENT_F:
  45. case DA9150_EVENT_G:
  46. case DA9150_EVENT_H:
  47. case DA9150_CONTROL_B:
  48. case DA9150_CONTROL_C:
  49. case DA9150_GPADC_MAN:
  50. case DA9150_GPADC_RES_A:
  51. case DA9150_GPADC_RES_B:
  52. case DA9150_ADETVB_CFG_C:
  53. case DA9150_ADETD_STAT:
  54. case DA9150_ADET_CMPSTAT:
  55. case DA9150_ADET_CTRL_A:
  56. case DA9150_PPR_TCTR_B:
  57. case DA9150_COREBTLD_STAT_A:
  58. case DA9150_CORE_DATA_A:
  59. case DA9150_CORE_DATA_B:
  60. case DA9150_CORE_DATA_C:
  61. case DA9150_CORE_DATA_D:
  62. case DA9150_CORE2WIRE_STAT_A:
  63. case DA9150_FW_CTRL_C:
  64. case DA9150_FG_CTRL_B:
  65. case DA9150_FW_CTRL_B:
  66. case DA9150_GPADC_CMAN:
  67. case DA9150_GPADC_CRES_A:
  68. case DA9150_GPADC_CRES_B:
  69. case DA9150_CC_ICHG_RES_A:
  70. case DA9150_CC_ICHG_RES_B:
  71. case DA9150_CC_IAVG_RES_A:
  72. case DA9150_CC_IAVG_RES_B:
  73. case DA9150_TAUX_CTRL_A:
  74. case DA9150_TAUX_VALUE_H:
  75. case DA9150_TAUX_VALUE_L:
  76. case DA9150_TBAT_RES_A:
  77. case DA9150_TBAT_RES_B:
  78. return true;
  79. default:
  80. return false;
  81. }
  82. }
  83. static const struct regmap_range_cfg da9150_range_cfg[] = {
  84. {
  85. .range_min = DA9150_PAGE_CON,
  86. .range_max = DA9150_TBAT_RES_B,
  87. .selector_reg = DA9150_PAGE_CON,
  88. .selector_mask = DA9150_I2C_PAGE_MASK,
  89. .selector_shift = DA9150_I2C_PAGE_SHIFT,
  90. .window_start = 0,
  91. .window_len = 256,
  92. },
  93. };
  94. static const struct regmap_config da9150_regmap_config = {
  95. .reg_bits = 8,
  96. .val_bits = 8,
  97. .ranges = da9150_range_cfg,
  98. .num_ranges = ARRAY_SIZE(da9150_range_cfg),
  99. .max_register = DA9150_TBAT_RES_B,
  100. .cache_type = REGCACHE_RBTREE,
  101. .volatile_reg = da9150_volatile_reg,
  102. };
  103. u8 da9150_reg_read(struct da9150 *da9150, u16 reg)
  104. {
  105. int val, ret;
  106. ret = regmap_read(da9150->regmap, reg, &val);
  107. if (ret)
  108. dev_err(da9150->dev, "Failed to read from reg 0x%x: %d\n",
  109. reg, ret);
  110. return (u8) val;
  111. }
  112. EXPORT_SYMBOL_GPL(da9150_reg_read);
  113. void da9150_reg_write(struct da9150 *da9150, u16 reg, u8 val)
  114. {
  115. int ret;
  116. ret = regmap_write(da9150->regmap, reg, val);
  117. if (ret)
  118. dev_err(da9150->dev, "Failed to write to reg 0x%x: %d\n",
  119. reg, ret);
  120. }
  121. EXPORT_SYMBOL_GPL(da9150_reg_write);
  122. void da9150_set_bits(struct da9150 *da9150, u16 reg, u8 mask, u8 val)
  123. {
  124. int ret;
  125. ret = regmap_update_bits(da9150->regmap, reg, mask, val);
  126. if (ret)
  127. dev_err(da9150->dev, "Failed to set bits in reg 0x%x: %d\n",
  128. reg, ret);
  129. }
  130. EXPORT_SYMBOL_GPL(da9150_set_bits);
  131. void da9150_bulk_read(struct da9150 *da9150, u16 reg, int count, u8 *buf)
  132. {
  133. int ret;
  134. ret = regmap_bulk_read(da9150->regmap, reg, buf, count);
  135. if (ret)
  136. dev_err(da9150->dev, "Failed to bulk read from reg 0x%x: %d\n",
  137. reg, ret);
  138. }
  139. EXPORT_SYMBOL_GPL(da9150_bulk_read);
  140. void da9150_bulk_write(struct da9150 *da9150, u16 reg, int count, const u8 *buf)
  141. {
  142. int ret;
  143. ret = regmap_raw_write(da9150->regmap, reg, buf, count);
  144. if (ret)
  145. dev_err(da9150->dev, "Failed to bulk write to reg 0x%x %d\n",
  146. reg, ret);
  147. }
  148. EXPORT_SYMBOL_GPL(da9150_bulk_write);
  149. static const struct regmap_irq da9150_irqs[] = {
  150. [DA9150_IRQ_VBUS] = {
  151. .reg_offset = 0,
  152. .mask = DA9150_E_VBUS_MASK,
  153. },
  154. [DA9150_IRQ_CHG] = {
  155. .reg_offset = 0,
  156. .mask = DA9150_E_CHG_MASK,
  157. },
  158. [DA9150_IRQ_TCLASS] = {
  159. .reg_offset = 0,
  160. .mask = DA9150_E_TCLASS_MASK,
  161. },
  162. [DA9150_IRQ_TJUNC] = {
  163. .reg_offset = 0,
  164. .mask = DA9150_E_TJUNC_MASK,
  165. },
  166. [DA9150_IRQ_VFAULT] = {
  167. .reg_offset = 0,
  168. .mask = DA9150_E_VFAULT_MASK,
  169. },
  170. [DA9150_IRQ_CONF] = {
  171. .reg_offset = 1,
  172. .mask = DA9150_E_CONF_MASK,
  173. },
  174. [DA9150_IRQ_DAT] = {
  175. .reg_offset = 1,
  176. .mask = DA9150_E_DAT_MASK,
  177. },
  178. [DA9150_IRQ_DTYPE] = {
  179. .reg_offset = 1,
  180. .mask = DA9150_E_DTYPE_MASK,
  181. },
  182. [DA9150_IRQ_ID] = {
  183. .reg_offset = 1,
  184. .mask = DA9150_E_ID_MASK,
  185. },
  186. [DA9150_IRQ_ADP] = {
  187. .reg_offset = 1,
  188. .mask = DA9150_E_ADP_MASK,
  189. },
  190. [DA9150_IRQ_SESS_END] = {
  191. .reg_offset = 1,
  192. .mask = DA9150_E_SESS_END_MASK,
  193. },
  194. [DA9150_IRQ_SESS_VLD] = {
  195. .reg_offset = 1,
  196. .mask = DA9150_E_SESS_VLD_MASK,
  197. },
  198. [DA9150_IRQ_FG] = {
  199. .reg_offset = 2,
  200. .mask = DA9150_E_FG_MASK,
  201. },
  202. [DA9150_IRQ_GP] = {
  203. .reg_offset = 2,
  204. .mask = DA9150_E_GP_MASK,
  205. },
  206. [DA9150_IRQ_TBAT] = {
  207. .reg_offset = 2,
  208. .mask = DA9150_E_TBAT_MASK,
  209. },
  210. [DA9150_IRQ_GPIOA] = {
  211. .reg_offset = 2,
  212. .mask = DA9150_E_GPIOA_MASK,
  213. },
  214. [DA9150_IRQ_GPIOB] = {
  215. .reg_offset = 2,
  216. .mask = DA9150_E_GPIOB_MASK,
  217. },
  218. [DA9150_IRQ_GPIOC] = {
  219. .reg_offset = 2,
  220. .mask = DA9150_E_GPIOC_MASK,
  221. },
  222. [DA9150_IRQ_GPIOD] = {
  223. .reg_offset = 2,
  224. .mask = DA9150_E_GPIOD_MASK,
  225. },
  226. [DA9150_IRQ_GPADC] = {
  227. .reg_offset = 2,
  228. .mask = DA9150_E_GPADC_MASK,
  229. },
  230. [DA9150_IRQ_WKUP] = {
  231. .reg_offset = 3,
  232. .mask = DA9150_E_WKUP_MASK,
  233. },
  234. };
  235. static const struct regmap_irq_chip da9150_regmap_irq_chip = {
  236. .name = "da9150_irq",
  237. .status_base = DA9150_EVENT_E,
  238. .mask_base = DA9150_IRQ_MASK_E,
  239. .ack_base = DA9150_EVENT_E,
  240. .num_regs = DA9150_NUM_IRQ_REGS,
  241. .irqs = da9150_irqs,
  242. .num_irqs = ARRAY_SIZE(da9150_irqs),
  243. };
  244. static struct resource da9150_gpadc_resources[] = {
  245. {
  246. .name = "GPADC",
  247. .start = DA9150_IRQ_GPADC,
  248. .end = DA9150_IRQ_GPADC,
  249. .flags = IORESOURCE_IRQ,
  250. },
  251. };
  252. static struct resource da9150_charger_resources[] = {
  253. {
  254. .name = "CHG_STATUS",
  255. .start = DA9150_IRQ_CHG,
  256. .end = DA9150_IRQ_CHG,
  257. .flags = IORESOURCE_IRQ,
  258. },
  259. {
  260. .name = "CHG_TJUNC",
  261. .start = DA9150_IRQ_TJUNC,
  262. .end = DA9150_IRQ_TJUNC,
  263. .flags = IORESOURCE_IRQ,
  264. },
  265. {
  266. .name = "CHG_VFAULT",
  267. .start = DA9150_IRQ_VFAULT,
  268. .end = DA9150_IRQ_VFAULT,
  269. .flags = IORESOURCE_IRQ,
  270. },
  271. {
  272. .name = "CHG_VBUS",
  273. .start = DA9150_IRQ_VBUS,
  274. .end = DA9150_IRQ_VBUS,
  275. .flags = IORESOURCE_IRQ,
  276. },
  277. };
  278. static struct mfd_cell da9150_devs[] = {
  279. {
  280. .name = "da9150-gpadc",
  281. .of_compatible = "dlg,da9150-gpadc",
  282. .resources = da9150_gpadc_resources,
  283. .num_resources = ARRAY_SIZE(da9150_gpadc_resources),
  284. },
  285. {
  286. .name = "da9150-charger",
  287. .of_compatible = "dlg,da9150-charger",
  288. .resources = da9150_charger_resources,
  289. .num_resources = ARRAY_SIZE(da9150_charger_resources),
  290. },
  291. };
  292. static int da9150_probe(struct i2c_client *client,
  293. const struct i2c_device_id *id)
  294. {
  295. struct da9150 *da9150;
  296. struct da9150_pdata *pdata = dev_get_platdata(&client->dev);
  297. int ret;
  298. da9150 = devm_kzalloc(&client->dev, sizeof(*da9150), GFP_KERNEL);
  299. if (!da9150)
  300. return -ENOMEM;
  301. da9150->dev = &client->dev;
  302. da9150->irq = client->irq;
  303. i2c_set_clientdata(client, da9150);
  304. da9150->regmap = devm_regmap_init_i2c(client, &da9150_regmap_config);
  305. if (IS_ERR(da9150->regmap)) {
  306. ret = PTR_ERR(da9150->regmap);
  307. dev_err(da9150->dev, "Failed to allocate register map: %d\n",
  308. ret);
  309. return ret;
  310. }
  311. da9150->irq_base = pdata ? pdata->irq_base : -1;
  312. ret = regmap_add_irq_chip(da9150->regmap, da9150->irq,
  313. IRQF_TRIGGER_LOW | IRQF_ONESHOT,
  314. da9150->irq_base, &da9150_regmap_irq_chip,
  315. &da9150->regmap_irq_data);
  316. if (ret)
  317. return ret;
  318. da9150->irq_base = regmap_irq_chip_get_base(da9150->regmap_irq_data);
  319. enable_irq_wake(da9150->irq);
  320. ret = mfd_add_devices(da9150->dev, -1, da9150_devs,
  321. ARRAY_SIZE(da9150_devs), NULL,
  322. da9150->irq_base, NULL);
  323. if (ret) {
  324. dev_err(da9150->dev, "Failed to add child devices: %d\n", ret);
  325. regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
  326. return ret;
  327. }
  328. return 0;
  329. }
  330. static int da9150_remove(struct i2c_client *client)
  331. {
  332. struct da9150 *da9150 = i2c_get_clientdata(client);
  333. regmap_del_irq_chip(da9150->irq, da9150->regmap_irq_data);
  334. mfd_remove_devices(da9150->dev);
  335. return 0;
  336. }
  337. static void da9150_shutdown(struct i2c_client *client)
  338. {
  339. struct da9150 *da9150 = i2c_get_clientdata(client);
  340. /* Make sure we have a wakup source for the device */
  341. da9150_set_bits(da9150, DA9150_CONFIG_D,
  342. DA9150_WKUP_PM_EN_MASK,
  343. DA9150_WKUP_PM_EN_MASK);
  344. /* Set device to DISABLED mode */
  345. da9150_set_bits(da9150, DA9150_CONTROL_C,
  346. DA9150_DISABLE_MASK, DA9150_DISABLE_MASK);
  347. }
  348. static const struct i2c_device_id da9150_i2c_id[] = {
  349. { "da9150", },
  350. { }
  351. };
  352. MODULE_DEVICE_TABLE(i2c, da9150_i2c_id);
  353. static const struct of_device_id da9150_of_match[] = {
  354. { .compatible = "dlg,da9150", },
  355. { }
  356. };
  357. MODULE_DEVICE_TABLE(of, da9150_of_match);
  358. static struct i2c_driver da9150_driver = {
  359. .driver = {
  360. .name = "da9150",
  361. .of_match_table = of_match_ptr(da9150_of_match),
  362. },
  363. .probe = da9150_probe,
  364. .remove = da9150_remove,
  365. .shutdown = da9150_shutdown,
  366. .id_table = da9150_i2c_id,
  367. };
  368. module_i2c_driver(da9150_driver);
  369. MODULE_DESCRIPTION("MFD Core Driver for DA9150");
  370. MODULE_AUTHOR("Adam Thomson <Adam.Thomson.Opensource@diasemi.com>");
  371. MODULE_LICENSE("GPL");