as3722.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470
  1. /*
  2. * Core driver for ams AS3722 PMICs
  3. *
  4. * Copyright (C) 2013 AMS AG
  5. * Copyright (c) 2013, NVIDIA Corporation. All rights reserved.
  6. *
  7. * Author: Florian Lobmaier <florian.lobmaier@ams.com>
  8. * Author: Laxman Dewangan <ldewangan@nvidia.com>
  9. *
  10. * This program is free software; you can redistribute it and/or modify
  11. * it under the terms of the GNU General Public License as published by
  12. * the Free Software Foundation; either version 2 of the License, or
  13. * (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, write to the Free Software
  22. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  23. */
  24. #include <linux/err.h>
  25. #include <linux/i2c.h>
  26. #include <linux/interrupt.h>
  27. #include <linux/irq.h>
  28. #include <linux/kernel.h>
  29. #include <linux/module.h>
  30. #include <linux/mfd/core.h>
  31. #include <linux/mfd/as3722.h>
  32. #include <linux/of.h>
  33. #include <linux/regmap.h>
  34. #include <linux/slab.h>
  35. #define AS3722_DEVICE_ID 0x0C
  36. static const struct resource as3722_rtc_resource[] = {
  37. {
  38. .name = "as3722-rtc-alarm",
  39. .start = AS3722_IRQ_RTC_ALARM,
  40. .end = AS3722_IRQ_RTC_ALARM,
  41. .flags = IORESOURCE_IRQ,
  42. },
  43. };
  44. static const struct resource as3722_adc_resource[] = {
  45. {
  46. .name = "as3722-adc",
  47. .start = AS3722_IRQ_ADC,
  48. .end = AS3722_IRQ_ADC,
  49. .flags = IORESOURCE_IRQ,
  50. },
  51. };
  52. static const struct mfd_cell as3722_devs[] = {
  53. {
  54. .name = "as3722-pinctrl",
  55. },
  56. {
  57. .name = "as3722-regulator",
  58. },
  59. {
  60. .name = "as3722-rtc",
  61. .num_resources = ARRAY_SIZE(as3722_rtc_resource),
  62. .resources = as3722_rtc_resource,
  63. },
  64. {
  65. .name = "as3722-adc",
  66. .num_resources = ARRAY_SIZE(as3722_adc_resource),
  67. .resources = as3722_adc_resource,
  68. },
  69. {
  70. .name = "as3722-power-off",
  71. },
  72. {
  73. .name = "as3722-wdt",
  74. },
  75. };
  76. static const struct regmap_irq as3722_irqs[] = {
  77. /* INT1 IRQs */
  78. [AS3722_IRQ_LID] = {
  79. .mask = AS3722_INTERRUPT_MASK1_LID,
  80. },
  81. [AS3722_IRQ_ACOK] = {
  82. .mask = AS3722_INTERRUPT_MASK1_ACOK,
  83. },
  84. [AS3722_IRQ_ENABLE1] = {
  85. .mask = AS3722_INTERRUPT_MASK1_ENABLE1,
  86. },
  87. [AS3722_IRQ_OCCUR_ALARM_SD0] = {
  88. .mask = AS3722_INTERRUPT_MASK1_OCURR_ALARM_SD0,
  89. },
  90. [AS3722_IRQ_ONKEY_LONG_PRESS] = {
  91. .mask = AS3722_INTERRUPT_MASK1_ONKEY_LONG,
  92. },
  93. [AS3722_IRQ_ONKEY] = {
  94. .mask = AS3722_INTERRUPT_MASK1_ONKEY,
  95. },
  96. [AS3722_IRQ_OVTMP] = {
  97. .mask = AS3722_INTERRUPT_MASK1_OVTMP,
  98. },
  99. [AS3722_IRQ_LOWBAT] = {
  100. .mask = AS3722_INTERRUPT_MASK1_LOWBAT,
  101. },
  102. /* INT2 IRQs */
  103. [AS3722_IRQ_SD0_LV] = {
  104. .mask = AS3722_INTERRUPT_MASK2_SD0_LV,
  105. .reg_offset = 1,
  106. },
  107. [AS3722_IRQ_SD1_LV] = {
  108. .mask = AS3722_INTERRUPT_MASK2_SD1_LV,
  109. .reg_offset = 1,
  110. },
  111. [AS3722_IRQ_SD2_LV] = {
  112. .mask = AS3722_INTERRUPT_MASK2_SD2345_LV,
  113. .reg_offset = 1,
  114. },
  115. [AS3722_IRQ_PWM1_OV_PROT] = {
  116. .mask = AS3722_INTERRUPT_MASK2_PWM1_OV_PROT,
  117. .reg_offset = 1,
  118. },
  119. [AS3722_IRQ_PWM2_OV_PROT] = {
  120. .mask = AS3722_INTERRUPT_MASK2_PWM2_OV_PROT,
  121. .reg_offset = 1,
  122. },
  123. [AS3722_IRQ_ENABLE2] = {
  124. .mask = AS3722_INTERRUPT_MASK2_ENABLE2,
  125. .reg_offset = 1,
  126. },
  127. [AS3722_IRQ_SD6_LV] = {
  128. .mask = AS3722_INTERRUPT_MASK2_SD6_LV,
  129. .reg_offset = 1,
  130. },
  131. [AS3722_IRQ_RTC_REP] = {
  132. .mask = AS3722_INTERRUPT_MASK2_RTC_REP,
  133. .reg_offset = 1,
  134. },
  135. /* INT3 IRQs */
  136. [AS3722_IRQ_RTC_ALARM] = {
  137. .mask = AS3722_INTERRUPT_MASK3_RTC_ALARM,
  138. .reg_offset = 2,
  139. },
  140. [AS3722_IRQ_GPIO1] = {
  141. .mask = AS3722_INTERRUPT_MASK3_GPIO1,
  142. .reg_offset = 2,
  143. },
  144. [AS3722_IRQ_GPIO2] = {
  145. .mask = AS3722_INTERRUPT_MASK3_GPIO2,
  146. .reg_offset = 2,
  147. },
  148. [AS3722_IRQ_GPIO3] = {
  149. .mask = AS3722_INTERRUPT_MASK3_GPIO3,
  150. .reg_offset = 2,
  151. },
  152. [AS3722_IRQ_GPIO4] = {
  153. .mask = AS3722_INTERRUPT_MASK3_GPIO4,
  154. .reg_offset = 2,
  155. },
  156. [AS3722_IRQ_GPIO5] = {
  157. .mask = AS3722_INTERRUPT_MASK3_GPIO5,
  158. .reg_offset = 2,
  159. },
  160. [AS3722_IRQ_WATCHDOG] = {
  161. .mask = AS3722_INTERRUPT_MASK3_WATCHDOG,
  162. .reg_offset = 2,
  163. },
  164. [AS3722_IRQ_ENABLE3] = {
  165. .mask = AS3722_INTERRUPT_MASK3_ENABLE3,
  166. .reg_offset = 2,
  167. },
  168. /* INT4 IRQs */
  169. [AS3722_IRQ_TEMP_SD0_SHUTDOWN] = {
  170. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD0_SHUTDOWN,
  171. .reg_offset = 3,
  172. },
  173. [AS3722_IRQ_TEMP_SD1_SHUTDOWN] = {
  174. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD1_SHUTDOWN,
  175. .reg_offset = 3,
  176. },
  177. [AS3722_IRQ_TEMP_SD2_SHUTDOWN] = {
  178. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD6_SHUTDOWN,
  179. .reg_offset = 3,
  180. },
  181. [AS3722_IRQ_TEMP_SD0_ALARM] = {
  182. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD0_ALARM,
  183. .reg_offset = 3,
  184. },
  185. [AS3722_IRQ_TEMP_SD1_ALARM] = {
  186. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD1_ALARM,
  187. .reg_offset = 3,
  188. },
  189. [AS3722_IRQ_TEMP_SD6_ALARM] = {
  190. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD6_ALARM,
  191. .reg_offset = 3,
  192. },
  193. [AS3722_IRQ_OCCUR_ALARM_SD6] = {
  194. .mask = AS3722_INTERRUPT_MASK4_OCCUR_ALARM_SD6,
  195. .reg_offset = 3,
  196. },
  197. [AS3722_IRQ_ADC] = {
  198. .mask = AS3722_INTERRUPT_MASK4_ADC,
  199. .reg_offset = 3,
  200. },
  201. };
  202. static const struct regmap_irq_chip as3722_irq_chip = {
  203. .name = "as3722",
  204. .irqs = as3722_irqs,
  205. .num_irqs = ARRAY_SIZE(as3722_irqs),
  206. .num_regs = 4,
  207. .status_base = AS3722_INTERRUPT_STATUS1_REG,
  208. .mask_base = AS3722_INTERRUPT_MASK1_REG,
  209. };
  210. static int as3722_check_device_id(struct as3722 *as3722)
  211. {
  212. u32 val;
  213. int ret;
  214. /* Check that this is actually a AS3722 */
  215. ret = as3722_read(as3722, AS3722_ASIC_ID1_REG, &val);
  216. if (ret < 0) {
  217. dev_err(as3722->dev, "ASIC_ID1 read failed: %d\n", ret);
  218. return ret;
  219. }
  220. if (val != AS3722_DEVICE_ID) {
  221. dev_err(as3722->dev, "Device is not AS3722, ID is 0x%x\n", val);
  222. return -ENODEV;
  223. }
  224. ret = as3722_read(as3722, AS3722_ASIC_ID2_REG, &val);
  225. if (ret < 0) {
  226. dev_err(as3722->dev, "ASIC_ID2 read failed: %d\n", ret);
  227. return ret;
  228. }
  229. dev_info(as3722->dev, "AS3722 with revision 0x%x found\n", val);
  230. return 0;
  231. }
  232. static int as3722_configure_pullups(struct as3722 *as3722)
  233. {
  234. int ret;
  235. u32 val = 0;
  236. if (as3722->en_intern_int_pullup)
  237. val |= AS3722_INT_PULL_UP;
  238. if (as3722->en_intern_i2c_pullup)
  239. val |= AS3722_I2C_PULL_UP;
  240. ret = as3722_update_bits(as3722, AS3722_IOVOLTAGE_REG,
  241. AS3722_INT_PULL_UP | AS3722_I2C_PULL_UP, val);
  242. if (ret < 0)
  243. dev_err(as3722->dev, "IOVOLTAGE_REG update failed: %d\n", ret);
  244. return ret;
  245. }
  246. static const struct regmap_range as3722_readable_ranges[] = {
  247. regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG),
  248. regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG),
  249. regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_REG_SEQU_MOD3_REG),
  250. regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG),
  251. regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG),
  252. regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG,
  253. AS3722_BATTERY_VOLTAGE_MONITOR2_REG),
  254. regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG),
  255. regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG),
  256. regmap_reg_range(AS3722_RTC_ACCESS_REG, AS3722_RTC_ACCESS_REG),
  257. regmap_reg_range(AS3722_RTC_STATUS_REG, AS3722_TEMP_STATUS_REG),
  258. regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC_CONFIGURATION_REG),
  259. regmap_reg_range(AS3722_ASIC_ID1_REG, AS3722_ASIC_ID2_REG),
  260. regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG),
  261. regmap_reg_range(AS3722_FUSE7_REG, AS3722_FUSE7_REG),
  262. };
  263. static const struct regmap_access_table as3722_readable_table = {
  264. .yes_ranges = as3722_readable_ranges,
  265. .n_yes_ranges = ARRAY_SIZE(as3722_readable_ranges),
  266. };
  267. static const struct regmap_range as3722_writable_ranges[] = {
  268. regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG),
  269. regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG),
  270. regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_GPIO_SIGNAL_OUT_REG),
  271. regmap_reg_range(AS3722_REG_SEQU_MOD1_REG, AS3722_REG_SEQU_MOD3_REG),
  272. regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG),
  273. regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG),
  274. regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG,
  275. AS3722_BATTERY_VOLTAGE_MONITOR2_REG),
  276. regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG),
  277. regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG),
  278. regmap_reg_range(AS3722_INTERRUPT_MASK1_REG, AS3722_TEMP_STATUS_REG),
  279. regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC1_CONTROL_REG),
  280. regmap_reg_range(AS3722_ADC1_THRESHOLD_HI_MSB_REG,
  281. AS3722_ADC_CONFIGURATION_REG),
  282. regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG),
  283. };
  284. static const struct regmap_access_table as3722_writable_table = {
  285. .yes_ranges = as3722_writable_ranges,
  286. .n_yes_ranges = ARRAY_SIZE(as3722_writable_ranges),
  287. };
  288. static const struct regmap_range as3722_cacheable_ranges[] = {
  289. regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_LDO11_VOLTAGE_REG),
  290. regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_LDOCONTROL1_REG),
  291. };
  292. static const struct regmap_access_table as3722_volatile_table = {
  293. .no_ranges = as3722_cacheable_ranges,
  294. .n_no_ranges = ARRAY_SIZE(as3722_cacheable_ranges),
  295. };
  296. static const struct regmap_config as3722_regmap_config = {
  297. .reg_bits = 8,
  298. .val_bits = 8,
  299. .max_register = AS3722_MAX_REGISTER,
  300. .cache_type = REGCACHE_RBTREE,
  301. .rd_table = &as3722_readable_table,
  302. .wr_table = &as3722_writable_table,
  303. .volatile_table = &as3722_volatile_table,
  304. };
  305. static int as3722_i2c_of_probe(struct i2c_client *i2c,
  306. struct as3722 *as3722)
  307. {
  308. struct device_node *np = i2c->dev.of_node;
  309. struct irq_data *irq_data;
  310. if (!np) {
  311. dev_err(&i2c->dev, "Device Tree not found\n");
  312. return -EINVAL;
  313. }
  314. irq_data = irq_get_irq_data(i2c->irq);
  315. if (!irq_data) {
  316. dev_err(&i2c->dev, "Invalid IRQ: %d\n", i2c->irq);
  317. return -EINVAL;
  318. }
  319. as3722->en_intern_int_pullup = of_property_read_bool(np,
  320. "ams,enable-internal-int-pullup");
  321. as3722->en_intern_i2c_pullup = of_property_read_bool(np,
  322. "ams,enable-internal-i2c-pullup");
  323. as3722->irq_flags = irqd_get_trigger_type(irq_data);
  324. dev_dbg(&i2c->dev, "IRQ flags are 0x%08lx\n", as3722->irq_flags);
  325. return 0;
  326. }
  327. static int as3722_i2c_probe(struct i2c_client *i2c,
  328. const struct i2c_device_id *id)
  329. {
  330. struct as3722 *as3722;
  331. unsigned long irq_flags;
  332. int ret;
  333. as3722 = devm_kzalloc(&i2c->dev, sizeof(struct as3722), GFP_KERNEL);
  334. if (!as3722)
  335. return -ENOMEM;
  336. as3722->dev = &i2c->dev;
  337. as3722->chip_irq = i2c->irq;
  338. i2c_set_clientdata(i2c, as3722);
  339. ret = as3722_i2c_of_probe(i2c, as3722);
  340. if (ret < 0)
  341. return ret;
  342. as3722->regmap = devm_regmap_init_i2c(i2c, &as3722_regmap_config);
  343. if (IS_ERR(as3722->regmap)) {
  344. ret = PTR_ERR(as3722->regmap);
  345. dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
  346. return ret;
  347. }
  348. ret = as3722_check_device_id(as3722);
  349. if (ret < 0)
  350. return ret;
  351. irq_flags = as3722->irq_flags | IRQF_ONESHOT;
  352. ret = devm_regmap_add_irq_chip(as3722->dev, as3722->regmap,
  353. as3722->chip_irq,
  354. irq_flags, -1, &as3722_irq_chip,
  355. &as3722->irq_data);
  356. if (ret < 0) {
  357. dev_err(as3722->dev, "Failed to add regmap irq: %d\n", ret);
  358. return ret;
  359. }
  360. ret = as3722_configure_pullups(as3722);
  361. if (ret < 0)
  362. return ret;
  363. ret = devm_mfd_add_devices(&i2c->dev, -1, as3722_devs,
  364. ARRAY_SIZE(as3722_devs), NULL, 0,
  365. regmap_irq_get_domain(as3722->irq_data));
  366. if (ret) {
  367. dev_err(as3722->dev, "Failed to add MFD devices: %d\n", ret);
  368. return ret;
  369. }
  370. device_init_wakeup(as3722->dev, true);
  371. dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n");
  372. return 0;
  373. }
  374. static int __maybe_unused as3722_i2c_suspend(struct device *dev)
  375. {
  376. struct as3722 *as3722 = dev_get_drvdata(dev);
  377. if (device_may_wakeup(dev))
  378. enable_irq_wake(as3722->chip_irq);
  379. disable_irq(as3722->chip_irq);
  380. return 0;
  381. }
  382. static int __maybe_unused as3722_i2c_resume(struct device *dev)
  383. {
  384. struct as3722 *as3722 = dev_get_drvdata(dev);
  385. enable_irq(as3722->chip_irq);
  386. if (device_may_wakeup(dev))
  387. disable_irq_wake(as3722->chip_irq);
  388. return 0;
  389. }
  390. static const struct of_device_id as3722_of_match[] = {
  391. { .compatible = "ams,as3722", },
  392. {},
  393. };
  394. MODULE_DEVICE_TABLE(of, as3722_of_match);
  395. static const struct i2c_device_id as3722_i2c_id[] = {
  396. { "as3722", 0 },
  397. {},
  398. };
  399. MODULE_DEVICE_TABLE(i2c, as3722_i2c_id);
  400. static const struct dev_pm_ops as3722_pm_ops = {
  401. SET_SYSTEM_SLEEP_PM_OPS(as3722_i2c_suspend, as3722_i2c_resume)
  402. };
  403. static struct i2c_driver as3722_i2c_driver = {
  404. .driver = {
  405. .name = "as3722",
  406. .of_match_table = as3722_of_match,
  407. .pm = &as3722_pm_ops,
  408. },
  409. .probe = as3722_i2c_probe,
  410. .id_table = as3722_i2c_id,
  411. };
  412. module_i2c_driver(as3722_i2c_driver);
  413. MODULE_DESCRIPTION("I2C support for AS3722 PMICs");
  414. MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>");
  415. MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
  416. MODULE_LICENSE("GPL");