da9062-core.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533
  1. /*
  2. * Core, IRQ and I2C device driver for DA9062 PMIC
  3. * Copyright (C) 2015 Dialog Semiconductor Ltd.
  4. *
  5. * This program is free software; you can redistribute it and/or
  6. * modify it under the terms of the GNU General Public License
  7. * as published by the Free Software Foundation; either version 2
  8. * of the License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. */
  15. #include <linux/kernel.h>
  16. #include <linux/module.h>
  17. #include <linux/init.h>
  18. #include <linux/device.h>
  19. #include <linux/interrupt.h>
  20. #include <linux/regmap.h>
  21. #include <linux/irq.h>
  22. #include <linux/mfd/core.h>
  23. #include <linux/i2c.h>
  24. #include <linux/mfd/da9062/core.h>
  25. #include <linux/mfd/da9062/registers.h>
  26. #include <linux/regulator/of_regulator.h>
  27. #define DA9062_REG_EVENT_A_OFFSET 0
  28. #define DA9062_REG_EVENT_B_OFFSET 1
  29. #define DA9062_REG_EVENT_C_OFFSET 2
  30. static struct regmap_irq da9062_irqs[] = {
  31. /* EVENT A */
  32. [DA9062_IRQ_ONKEY] = {
  33. .reg_offset = DA9062_REG_EVENT_A_OFFSET,
  34. .mask = DA9062AA_M_NONKEY_MASK,
  35. },
  36. [DA9062_IRQ_ALARM] = {
  37. .reg_offset = DA9062_REG_EVENT_A_OFFSET,
  38. .mask = DA9062AA_M_ALARM_MASK,
  39. },
  40. [DA9062_IRQ_TICK] = {
  41. .reg_offset = DA9062_REG_EVENT_A_OFFSET,
  42. .mask = DA9062AA_M_TICK_MASK,
  43. },
  44. [DA9062_IRQ_WDG_WARN] = {
  45. .reg_offset = DA9062_REG_EVENT_A_OFFSET,
  46. .mask = DA9062AA_M_WDG_WARN_MASK,
  47. },
  48. [DA9062_IRQ_SEQ_RDY] = {
  49. .reg_offset = DA9062_REG_EVENT_A_OFFSET,
  50. .mask = DA9062AA_M_SEQ_RDY_MASK,
  51. },
  52. /* EVENT B */
  53. [DA9062_IRQ_TEMP] = {
  54. .reg_offset = DA9062_REG_EVENT_B_OFFSET,
  55. .mask = DA9062AA_M_TEMP_MASK,
  56. },
  57. [DA9062_IRQ_LDO_LIM] = {
  58. .reg_offset = DA9062_REG_EVENT_B_OFFSET,
  59. .mask = DA9062AA_M_LDO_LIM_MASK,
  60. },
  61. [DA9062_IRQ_DVC_RDY] = {
  62. .reg_offset = DA9062_REG_EVENT_B_OFFSET,
  63. .mask = DA9062AA_M_DVC_RDY_MASK,
  64. },
  65. [DA9062_IRQ_VDD_WARN] = {
  66. .reg_offset = DA9062_REG_EVENT_B_OFFSET,
  67. .mask = DA9062AA_M_VDD_WARN_MASK,
  68. },
  69. /* EVENT C */
  70. [DA9062_IRQ_GPI0] = {
  71. .reg_offset = DA9062_REG_EVENT_C_OFFSET,
  72. .mask = DA9062AA_M_GPI0_MASK,
  73. },
  74. [DA9062_IRQ_GPI1] = {
  75. .reg_offset = DA9062_REG_EVENT_C_OFFSET,
  76. .mask = DA9062AA_M_GPI1_MASK,
  77. },
  78. [DA9062_IRQ_GPI2] = {
  79. .reg_offset = DA9062_REG_EVENT_C_OFFSET,
  80. .mask = DA9062AA_M_GPI2_MASK,
  81. },
  82. [DA9062_IRQ_GPI3] = {
  83. .reg_offset = DA9062_REG_EVENT_C_OFFSET,
  84. .mask = DA9062AA_M_GPI3_MASK,
  85. },
  86. [DA9062_IRQ_GPI4] = {
  87. .reg_offset = DA9062_REG_EVENT_C_OFFSET,
  88. .mask = DA9062AA_M_GPI4_MASK,
  89. },
  90. };
  91. static struct regmap_irq_chip da9062_irq_chip = {
  92. .name = "da9062-irq",
  93. .irqs = da9062_irqs,
  94. .num_irqs = DA9062_NUM_IRQ,
  95. .num_regs = 3,
  96. .status_base = DA9062AA_EVENT_A,
  97. .mask_base = DA9062AA_IRQ_MASK_A,
  98. .ack_base = DA9062AA_EVENT_A,
  99. };
  100. static struct resource da9062_core_resources[] = {
  101. DEFINE_RES_NAMED(DA9062_IRQ_VDD_WARN, 1, "VDD_WARN", IORESOURCE_IRQ),
  102. };
  103. static struct resource da9062_regulators_resources[] = {
  104. DEFINE_RES_NAMED(DA9062_IRQ_LDO_LIM, 1, "LDO_LIM", IORESOURCE_IRQ),
  105. };
  106. static struct resource da9062_thermal_resources[] = {
  107. DEFINE_RES_NAMED(DA9062_IRQ_TEMP, 1, "THERMAL", IORESOURCE_IRQ),
  108. };
  109. static struct resource da9062_wdt_resources[] = {
  110. DEFINE_RES_NAMED(DA9062_IRQ_WDG_WARN, 1, "WD_WARN", IORESOURCE_IRQ),
  111. };
  112. static struct resource da9062_rtc_resources[] = {
  113. DEFINE_RES_NAMED(DA9062_IRQ_ALARM, 1, "ALARM", IORESOURCE_IRQ),
  114. DEFINE_RES_NAMED(DA9062_IRQ_TICK, 1, "TICK", IORESOURCE_IRQ),
  115. };
  116. static struct resource da9062_onkey_resources[] = {
  117. DEFINE_RES_NAMED(DA9062_IRQ_ONKEY, 1, "ONKEY", IORESOURCE_IRQ),
  118. };
  119. static const struct mfd_cell da9062_devs[] = {
  120. {
  121. .name = "da9062-core",
  122. .num_resources = ARRAY_SIZE(da9062_core_resources),
  123. .resources = da9062_core_resources,
  124. },
  125. {
  126. .name = "da9062-regulators",
  127. .num_resources = ARRAY_SIZE(da9062_regulators_resources),
  128. .resources = da9062_regulators_resources,
  129. },
  130. {
  131. .name = "da9062-watchdog",
  132. .num_resources = ARRAY_SIZE(da9062_wdt_resources),
  133. .resources = da9062_wdt_resources,
  134. .of_compatible = "dlg,da9062-wdt",
  135. },
  136. {
  137. .name = "da9062-thermal",
  138. .num_resources = ARRAY_SIZE(da9062_thermal_resources),
  139. .resources = da9062_thermal_resources,
  140. .of_compatible = "dlg,da9062-thermal",
  141. },
  142. {
  143. .name = "da9062-rtc",
  144. .num_resources = ARRAY_SIZE(da9062_rtc_resources),
  145. .resources = da9062_rtc_resources,
  146. .of_compatible = "dlg,da9062-rtc",
  147. },
  148. {
  149. .name = "da9062-onkey",
  150. .num_resources = ARRAY_SIZE(da9062_onkey_resources),
  151. .resources = da9062_onkey_resources,
  152. .of_compatible = "dlg,da9062-onkey",
  153. },
  154. };
  155. static int da9062_clear_fault_log(struct da9062 *chip)
  156. {
  157. int ret;
  158. int fault_log;
  159. ret = regmap_read(chip->regmap, DA9062AA_FAULT_LOG, &fault_log);
  160. if (ret < 0)
  161. return ret;
  162. if (fault_log) {
  163. if (fault_log & DA9062AA_TWD_ERROR_MASK)
  164. dev_dbg(chip->dev, "Fault log entry detected: TWD_ERROR\n");
  165. if (fault_log & DA9062AA_POR_MASK)
  166. dev_dbg(chip->dev, "Fault log entry detected: POR\n");
  167. if (fault_log & DA9062AA_VDD_FAULT_MASK)
  168. dev_dbg(chip->dev, "Fault log entry detected: VDD_FAULT\n");
  169. if (fault_log & DA9062AA_VDD_START_MASK)
  170. dev_dbg(chip->dev, "Fault log entry detected: VDD_START\n");
  171. if (fault_log & DA9062AA_TEMP_CRIT_MASK)
  172. dev_dbg(chip->dev, "Fault log entry detected: TEMP_CRIT\n");
  173. if (fault_log & DA9062AA_KEY_RESET_MASK)
  174. dev_dbg(chip->dev, "Fault log entry detected: KEY_RESET\n");
  175. if (fault_log & DA9062AA_NSHUTDOWN_MASK)
  176. dev_dbg(chip->dev, "Fault log entry detected: NSHUTDOWN\n");
  177. if (fault_log & DA9062AA_WAIT_SHUT_MASK)
  178. dev_dbg(chip->dev, "Fault log entry detected: WAIT_SHUT\n");
  179. ret = regmap_write(chip->regmap, DA9062AA_FAULT_LOG,
  180. fault_log);
  181. }
  182. return ret;
  183. }
  184. static int da9062_get_device_type(struct da9062 *chip)
  185. {
  186. int device_id, variant_id, variant_mrc;
  187. int ret;
  188. ret = regmap_read(chip->regmap, DA9062AA_DEVICE_ID, &device_id);
  189. if (ret < 0) {
  190. dev_err(chip->dev, "Cannot read chip ID.\n");
  191. return -EIO;
  192. }
  193. if (device_id != DA9062_PMIC_DEVICE_ID) {
  194. dev_err(chip->dev, "Invalid device ID: 0x%02x\n", device_id);
  195. return -ENODEV;
  196. }
  197. ret = regmap_read(chip->regmap, DA9062AA_VARIANT_ID, &variant_id);
  198. if (ret < 0) {
  199. dev_err(chip->dev, "Cannot read chip variant id.\n");
  200. return -EIO;
  201. }
  202. dev_info(chip->dev,
  203. "Device detected (device-ID: 0x%02X, var-ID: 0x%02X)\n",
  204. device_id, variant_id);
  205. variant_mrc = (variant_id & DA9062AA_MRC_MASK) >> DA9062AA_MRC_SHIFT;
  206. if (variant_mrc < DA9062_PMIC_VARIANT_MRC_AA) {
  207. dev_err(chip->dev,
  208. "Cannot support variant MRC: 0x%02X\n", variant_mrc);
  209. return -ENODEV;
  210. }
  211. return ret;
  212. }
  213. static const struct regmap_range da9062_aa_readable_ranges[] = {
  214. {
  215. .range_min = DA9062AA_PAGE_CON,
  216. .range_max = DA9062AA_STATUS_B,
  217. }, {
  218. .range_min = DA9062AA_STATUS_D,
  219. .range_max = DA9062AA_EVENT_C,
  220. }, {
  221. .range_min = DA9062AA_IRQ_MASK_A,
  222. .range_max = DA9062AA_IRQ_MASK_C,
  223. }, {
  224. .range_min = DA9062AA_CONTROL_A,
  225. .range_max = DA9062AA_GPIO_4,
  226. }, {
  227. .range_min = DA9062AA_GPIO_WKUP_MODE,
  228. .range_max = DA9062AA_BUCK4_CONT,
  229. }, {
  230. .range_min = DA9062AA_BUCK3_CONT,
  231. .range_max = DA9062AA_BUCK3_CONT,
  232. }, {
  233. .range_min = DA9062AA_LDO1_CONT,
  234. .range_max = DA9062AA_LDO4_CONT,
  235. }, {
  236. .range_min = DA9062AA_DVC_1,
  237. .range_max = DA9062AA_DVC_1,
  238. }, {
  239. .range_min = DA9062AA_COUNT_S,
  240. .range_max = DA9062AA_SECOND_D,
  241. }, {
  242. .range_min = DA9062AA_SEQ,
  243. .range_max = DA9062AA_ID_4_3,
  244. }, {
  245. .range_min = DA9062AA_ID_12_11,
  246. .range_max = DA9062AA_ID_16_15,
  247. }, {
  248. .range_min = DA9062AA_ID_22_21,
  249. .range_max = DA9062AA_ID_32_31,
  250. }, {
  251. .range_min = DA9062AA_SEQ_A,
  252. .range_max = DA9062AA_BUCK3_CFG,
  253. }, {
  254. .range_min = DA9062AA_VBUCK2_A,
  255. .range_max = DA9062AA_VBUCK4_A,
  256. }, {
  257. .range_min = DA9062AA_VBUCK3_A,
  258. .range_max = DA9062AA_VBUCK3_A,
  259. }, {
  260. .range_min = DA9062AA_VLDO1_A,
  261. .range_max = DA9062AA_VLDO4_A,
  262. }, {
  263. .range_min = DA9062AA_VBUCK2_B,
  264. .range_max = DA9062AA_VBUCK4_B,
  265. }, {
  266. .range_min = DA9062AA_VBUCK3_B,
  267. .range_max = DA9062AA_VBUCK3_B,
  268. }, {
  269. .range_min = DA9062AA_VLDO1_B,
  270. .range_max = DA9062AA_VLDO4_B,
  271. }, {
  272. .range_min = DA9062AA_BBAT_CONT,
  273. .range_max = DA9062AA_BBAT_CONT,
  274. }, {
  275. .range_min = DA9062AA_INTERFACE,
  276. .range_max = DA9062AA_CONFIG_E,
  277. }, {
  278. .range_min = DA9062AA_CONFIG_G,
  279. .range_max = DA9062AA_CONFIG_K,
  280. }, {
  281. .range_min = DA9062AA_CONFIG_M,
  282. .range_max = DA9062AA_CONFIG_M,
  283. }, {
  284. .range_min = DA9062AA_TRIM_CLDR,
  285. .range_max = DA9062AA_GP_ID_19,
  286. }, {
  287. .range_min = DA9062AA_DEVICE_ID,
  288. .range_max = DA9062AA_CONFIG_ID,
  289. },
  290. };
  291. static const struct regmap_range da9062_aa_writeable_ranges[] = {
  292. {
  293. .range_min = DA9062AA_PAGE_CON,
  294. .range_max = DA9062AA_PAGE_CON,
  295. }, {
  296. .range_min = DA9062AA_FAULT_LOG,
  297. .range_max = DA9062AA_EVENT_C,
  298. }, {
  299. .range_min = DA9062AA_IRQ_MASK_A,
  300. .range_max = DA9062AA_IRQ_MASK_C,
  301. }, {
  302. .range_min = DA9062AA_CONTROL_A,
  303. .range_max = DA9062AA_GPIO_4,
  304. }, {
  305. .range_min = DA9062AA_GPIO_WKUP_MODE,
  306. .range_max = DA9062AA_BUCK4_CONT,
  307. }, {
  308. .range_min = DA9062AA_BUCK3_CONT,
  309. .range_max = DA9062AA_BUCK3_CONT,
  310. }, {
  311. .range_min = DA9062AA_LDO1_CONT,
  312. .range_max = DA9062AA_LDO4_CONT,
  313. }, {
  314. .range_min = DA9062AA_DVC_1,
  315. .range_max = DA9062AA_DVC_1,
  316. }, {
  317. .range_min = DA9062AA_COUNT_S,
  318. .range_max = DA9062AA_ALARM_Y,
  319. }, {
  320. .range_min = DA9062AA_SEQ,
  321. .range_max = DA9062AA_ID_4_3,
  322. }, {
  323. .range_min = DA9062AA_ID_12_11,
  324. .range_max = DA9062AA_ID_16_15,
  325. }, {
  326. .range_min = DA9062AA_ID_22_21,
  327. .range_max = DA9062AA_ID_32_31,
  328. }, {
  329. .range_min = DA9062AA_SEQ_A,
  330. .range_max = DA9062AA_BUCK3_CFG,
  331. }, {
  332. .range_min = DA9062AA_VBUCK2_A,
  333. .range_max = DA9062AA_VBUCK4_A,
  334. }, {
  335. .range_min = DA9062AA_VBUCK3_A,
  336. .range_max = DA9062AA_VBUCK3_A,
  337. }, {
  338. .range_min = DA9062AA_VLDO1_A,
  339. .range_max = DA9062AA_VLDO4_A,
  340. }, {
  341. .range_min = DA9062AA_VBUCK2_B,
  342. .range_max = DA9062AA_VBUCK4_B,
  343. }, {
  344. .range_min = DA9062AA_VBUCK3_B,
  345. .range_max = DA9062AA_VBUCK3_B,
  346. }, {
  347. .range_min = DA9062AA_VLDO1_B,
  348. .range_max = DA9062AA_VLDO4_B,
  349. }, {
  350. .range_min = DA9062AA_BBAT_CONT,
  351. .range_max = DA9062AA_BBAT_CONT,
  352. }, {
  353. .range_min = DA9062AA_GP_ID_0,
  354. .range_max = DA9062AA_GP_ID_19,
  355. },
  356. };
  357. static const struct regmap_range da9062_aa_volatile_ranges[] = {
  358. {
  359. .range_min = DA9062AA_PAGE_CON,
  360. .range_max = DA9062AA_STATUS_B,
  361. }, {
  362. .range_min = DA9062AA_STATUS_D,
  363. .range_max = DA9062AA_EVENT_C,
  364. }, {
  365. .range_min = DA9062AA_CONTROL_F,
  366. .range_max = DA9062AA_CONTROL_F,
  367. }, {
  368. .range_min = DA9062AA_COUNT_S,
  369. .range_max = DA9062AA_SECOND_D,
  370. },
  371. };
  372. static const struct regmap_access_table da9062_aa_readable_table = {
  373. .yes_ranges = da9062_aa_readable_ranges,
  374. .n_yes_ranges = ARRAY_SIZE(da9062_aa_readable_ranges),
  375. };
  376. static const struct regmap_access_table da9062_aa_writeable_table = {
  377. .yes_ranges = da9062_aa_writeable_ranges,
  378. .n_yes_ranges = ARRAY_SIZE(da9062_aa_writeable_ranges),
  379. };
  380. static const struct regmap_access_table da9062_aa_volatile_table = {
  381. .yes_ranges = da9062_aa_volatile_ranges,
  382. .n_yes_ranges = ARRAY_SIZE(da9062_aa_volatile_ranges),
  383. };
  384. static const struct regmap_range_cfg da9062_range_cfg[] = {
  385. {
  386. .range_min = DA9062AA_PAGE_CON,
  387. .range_max = DA9062AA_CONFIG_ID,
  388. .selector_reg = DA9062AA_PAGE_CON,
  389. .selector_mask = 1 << DA9062_I2C_PAGE_SEL_SHIFT,
  390. .selector_shift = DA9062_I2C_PAGE_SEL_SHIFT,
  391. .window_start = 0,
  392. .window_len = 256,
  393. }
  394. };
  395. static struct regmap_config da9062_regmap_config = {
  396. .reg_bits = 8,
  397. .val_bits = 8,
  398. .ranges = da9062_range_cfg,
  399. .num_ranges = ARRAY_SIZE(da9062_range_cfg),
  400. .max_register = DA9062AA_CONFIG_ID,
  401. .cache_type = REGCACHE_RBTREE,
  402. .rd_table = &da9062_aa_readable_table,
  403. .wr_table = &da9062_aa_writeable_table,
  404. .volatile_table = &da9062_aa_volatile_table,
  405. };
  406. static int da9062_i2c_probe(struct i2c_client *i2c,
  407. const struct i2c_device_id *id)
  408. {
  409. struct da9062 *chip;
  410. unsigned int irq_base;
  411. int ret;
  412. chip = devm_kzalloc(&i2c->dev, sizeof(*chip), GFP_KERNEL);
  413. if (!chip)
  414. return -ENOMEM;
  415. i2c_set_clientdata(i2c, chip);
  416. chip->dev = &i2c->dev;
  417. if (!i2c->irq) {
  418. dev_err(chip->dev, "No IRQ configured\n");
  419. return -EINVAL;
  420. }
  421. chip->regmap = devm_regmap_init_i2c(i2c, &da9062_regmap_config);
  422. if (IS_ERR(chip->regmap)) {
  423. ret = PTR_ERR(chip->regmap);
  424. dev_err(chip->dev, "Failed to allocate register map: %d\n",
  425. ret);
  426. return ret;
  427. }
  428. ret = da9062_clear_fault_log(chip);
  429. if (ret < 0)
  430. dev_warn(chip->dev, "Cannot clear fault log\n");
  431. ret = da9062_get_device_type(chip);
  432. if (ret)
  433. return ret;
  434. ret = regmap_add_irq_chip(chip->regmap, i2c->irq,
  435. IRQF_TRIGGER_LOW | IRQF_ONESHOT | IRQF_SHARED,
  436. -1, &da9062_irq_chip,
  437. &chip->regmap_irq);
  438. if (ret) {
  439. dev_err(chip->dev, "Failed to request IRQ %d: %d\n",
  440. i2c->irq, ret);
  441. return ret;
  442. }
  443. irq_base = regmap_irq_chip_get_base(chip->regmap_irq);
  444. ret = mfd_add_devices(chip->dev, PLATFORM_DEVID_NONE, da9062_devs,
  445. ARRAY_SIZE(da9062_devs), NULL, irq_base,
  446. NULL);
  447. if (ret) {
  448. dev_err(chip->dev, "Cannot register child devices\n");
  449. regmap_del_irq_chip(i2c->irq, chip->regmap_irq);
  450. return ret;
  451. }
  452. return ret;
  453. }
  454. static int da9062_i2c_remove(struct i2c_client *i2c)
  455. {
  456. struct da9062 *chip = i2c_get_clientdata(i2c);
  457. mfd_remove_devices(chip->dev);
  458. regmap_del_irq_chip(i2c->irq, chip->regmap_irq);
  459. return 0;
  460. }
  461. static const struct i2c_device_id da9062_i2c_id[] = {
  462. { "da9062", 0 },
  463. { },
  464. };
  465. MODULE_DEVICE_TABLE(i2c, da9062_i2c_id);
  466. static const struct of_device_id da9062_dt_ids[] = {
  467. { .compatible = "dlg,da9062", },
  468. { }
  469. };
  470. MODULE_DEVICE_TABLE(of, da9062_dt_ids);
  471. static struct i2c_driver da9062_i2c_driver = {
  472. .driver = {
  473. .name = "da9062",
  474. .of_match_table = of_match_ptr(da9062_dt_ids),
  475. },
  476. .probe = da9062_i2c_probe,
  477. .remove = da9062_i2c_remove,
  478. .id_table = da9062_i2c_id,
  479. };
  480. module_i2c_driver(da9062_i2c_driver);
  481. MODULE_DESCRIPTION("Core device driver for Dialog DA9062");
  482. MODULE_AUTHOR("Steve Twiss <stwiss.opensource@diasemi.com>");
  483. MODULE_LICENSE("GPL");