as3722.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449
  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 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. static const struct regmap_irq as3722_irqs[] = {
  74. /* INT1 IRQs */
  75. [AS3722_IRQ_LID] = {
  76. .mask = AS3722_INTERRUPT_MASK1_LID,
  77. },
  78. [AS3722_IRQ_ACOK] = {
  79. .mask = AS3722_INTERRUPT_MASK1_ACOK,
  80. },
  81. [AS3722_IRQ_ENABLE1] = {
  82. .mask = AS3722_INTERRUPT_MASK1_ENABLE1,
  83. },
  84. [AS3722_IRQ_OCCUR_ALARM_SD0] = {
  85. .mask = AS3722_INTERRUPT_MASK1_OCURR_ALARM_SD0,
  86. },
  87. [AS3722_IRQ_ONKEY_LONG_PRESS] = {
  88. .mask = AS3722_INTERRUPT_MASK1_ONKEY_LONG,
  89. },
  90. [AS3722_IRQ_ONKEY] = {
  91. .mask = AS3722_INTERRUPT_MASK1_ONKEY,
  92. },
  93. [AS3722_IRQ_OVTMP] = {
  94. .mask = AS3722_INTERRUPT_MASK1_OVTMP,
  95. },
  96. [AS3722_IRQ_LOWBAT] = {
  97. .mask = AS3722_INTERRUPT_MASK1_LOWBAT,
  98. },
  99. /* INT2 IRQs */
  100. [AS3722_IRQ_SD0_LV] = {
  101. .mask = AS3722_INTERRUPT_MASK2_SD0_LV,
  102. .reg_offset = 1,
  103. },
  104. [AS3722_IRQ_SD1_LV] = {
  105. .mask = AS3722_INTERRUPT_MASK2_SD1_LV,
  106. .reg_offset = 1,
  107. },
  108. [AS3722_IRQ_SD2_LV] = {
  109. .mask = AS3722_INTERRUPT_MASK2_SD2345_LV,
  110. .reg_offset = 1,
  111. },
  112. [AS3722_IRQ_PWM1_OV_PROT] = {
  113. .mask = AS3722_INTERRUPT_MASK2_PWM1_OV_PROT,
  114. .reg_offset = 1,
  115. },
  116. [AS3722_IRQ_PWM2_OV_PROT] = {
  117. .mask = AS3722_INTERRUPT_MASK2_PWM2_OV_PROT,
  118. .reg_offset = 1,
  119. },
  120. [AS3722_IRQ_ENABLE2] = {
  121. .mask = AS3722_INTERRUPT_MASK2_ENABLE2,
  122. .reg_offset = 1,
  123. },
  124. [AS3722_IRQ_SD6_LV] = {
  125. .mask = AS3722_INTERRUPT_MASK2_SD6_LV,
  126. .reg_offset = 1,
  127. },
  128. [AS3722_IRQ_RTC_REP] = {
  129. .mask = AS3722_INTERRUPT_MASK2_RTC_REP,
  130. .reg_offset = 1,
  131. },
  132. /* INT3 IRQs */
  133. [AS3722_IRQ_RTC_ALARM] = {
  134. .mask = AS3722_INTERRUPT_MASK3_RTC_ALARM,
  135. .reg_offset = 2,
  136. },
  137. [AS3722_IRQ_GPIO1] = {
  138. .mask = AS3722_INTERRUPT_MASK3_GPIO1,
  139. .reg_offset = 2,
  140. },
  141. [AS3722_IRQ_GPIO2] = {
  142. .mask = AS3722_INTERRUPT_MASK3_GPIO2,
  143. .reg_offset = 2,
  144. },
  145. [AS3722_IRQ_GPIO3] = {
  146. .mask = AS3722_INTERRUPT_MASK3_GPIO3,
  147. .reg_offset = 2,
  148. },
  149. [AS3722_IRQ_GPIO4] = {
  150. .mask = AS3722_INTERRUPT_MASK3_GPIO4,
  151. .reg_offset = 2,
  152. },
  153. [AS3722_IRQ_GPIO5] = {
  154. .mask = AS3722_INTERRUPT_MASK3_GPIO5,
  155. .reg_offset = 2,
  156. },
  157. [AS3722_IRQ_WATCHDOG] = {
  158. .mask = AS3722_INTERRUPT_MASK3_WATCHDOG,
  159. .reg_offset = 2,
  160. },
  161. [AS3722_IRQ_ENABLE3] = {
  162. .mask = AS3722_INTERRUPT_MASK3_ENABLE3,
  163. .reg_offset = 2,
  164. },
  165. /* INT4 IRQs */
  166. [AS3722_IRQ_TEMP_SD0_SHUTDOWN] = {
  167. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD0_SHUTDOWN,
  168. .reg_offset = 3,
  169. },
  170. [AS3722_IRQ_TEMP_SD1_SHUTDOWN] = {
  171. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD1_SHUTDOWN,
  172. .reg_offset = 3,
  173. },
  174. [AS3722_IRQ_TEMP_SD2_SHUTDOWN] = {
  175. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD6_SHUTDOWN,
  176. .reg_offset = 3,
  177. },
  178. [AS3722_IRQ_TEMP_SD0_ALARM] = {
  179. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD0_ALARM,
  180. .reg_offset = 3,
  181. },
  182. [AS3722_IRQ_TEMP_SD1_ALARM] = {
  183. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD1_ALARM,
  184. .reg_offset = 3,
  185. },
  186. [AS3722_IRQ_TEMP_SD6_ALARM] = {
  187. .mask = AS3722_INTERRUPT_MASK4_TEMP_SD6_ALARM,
  188. .reg_offset = 3,
  189. },
  190. [AS3722_IRQ_OCCUR_ALARM_SD6] = {
  191. .mask = AS3722_INTERRUPT_MASK4_OCCUR_ALARM_SD6,
  192. .reg_offset = 3,
  193. },
  194. [AS3722_IRQ_ADC] = {
  195. .mask = AS3722_INTERRUPT_MASK4_ADC,
  196. .reg_offset = 3,
  197. },
  198. };
  199. static const struct regmap_irq_chip as3722_irq_chip = {
  200. .name = "as3722",
  201. .irqs = as3722_irqs,
  202. .num_irqs = ARRAY_SIZE(as3722_irqs),
  203. .num_regs = 4,
  204. .status_base = AS3722_INTERRUPT_STATUS1_REG,
  205. .mask_base = AS3722_INTERRUPT_MASK1_REG,
  206. };
  207. static int as3722_check_device_id(struct as3722 *as3722)
  208. {
  209. u32 val;
  210. int ret;
  211. /* Check that this is actually a AS3722 */
  212. ret = as3722_read(as3722, AS3722_ASIC_ID1_REG, &val);
  213. if (ret < 0) {
  214. dev_err(as3722->dev, "ASIC_ID1 read failed: %d\n", ret);
  215. return ret;
  216. }
  217. if (val != AS3722_DEVICE_ID) {
  218. dev_err(as3722->dev, "Device is not AS3722, ID is 0x%x\n", val);
  219. return -ENODEV;
  220. }
  221. ret = as3722_read(as3722, AS3722_ASIC_ID2_REG, &val);
  222. if (ret < 0) {
  223. dev_err(as3722->dev, "ASIC_ID2 read failed: %d\n", ret);
  224. return ret;
  225. }
  226. dev_info(as3722->dev, "AS3722 with revision 0x%x found\n", val);
  227. return 0;
  228. }
  229. static int as3722_configure_pullups(struct as3722 *as3722)
  230. {
  231. int ret;
  232. u32 val = 0;
  233. if (as3722->en_intern_int_pullup)
  234. val |= AS3722_INT_PULL_UP;
  235. if (as3722->en_intern_i2c_pullup)
  236. val |= AS3722_I2C_PULL_UP;
  237. ret = as3722_update_bits(as3722, AS3722_IOVOLTAGE_REG,
  238. AS3722_INT_PULL_UP | AS3722_I2C_PULL_UP, val);
  239. if (ret < 0)
  240. dev_err(as3722->dev, "IOVOLTAGE_REG update failed: %d\n", ret);
  241. return ret;
  242. }
  243. static const struct regmap_range as3722_readable_ranges[] = {
  244. regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG),
  245. regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG),
  246. regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_REG_SEQU_MOD3_REG),
  247. regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG),
  248. regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG),
  249. regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG,
  250. AS3722_BATTERY_VOLTAGE_MONITOR2_REG),
  251. regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG),
  252. regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG),
  253. regmap_reg_range(AS3722_RTC_ACCESS_REG, AS3722_RTC_ACCESS_REG),
  254. regmap_reg_range(AS3722_RTC_STATUS_REG, AS3722_TEMP_STATUS_REG),
  255. regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC_CONFIGURATION_REG),
  256. regmap_reg_range(AS3722_ASIC_ID1_REG, AS3722_ASIC_ID2_REG),
  257. regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG),
  258. };
  259. static const struct regmap_access_table as3722_readable_table = {
  260. .yes_ranges = as3722_readable_ranges,
  261. .n_yes_ranges = ARRAY_SIZE(as3722_readable_ranges),
  262. };
  263. static const struct regmap_range as3722_writable_ranges[] = {
  264. regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_SD6_VOLTAGE_REG),
  265. regmap_reg_range(AS3722_GPIO0_CONTROL_REG, AS3722_LDO7_VOLTAGE_REG),
  266. regmap_reg_range(AS3722_LDO9_VOLTAGE_REG, AS3722_GPIO_SIGNAL_OUT_REG),
  267. regmap_reg_range(AS3722_REG_SEQU_MOD1_REG, AS3722_REG_SEQU_MOD3_REG),
  268. regmap_reg_range(AS3722_SD_PHSW_CTRL_REG, AS3722_PWM_CONTROL_H_REG),
  269. regmap_reg_range(AS3722_WATCHDOG_TIMER_REG, AS3722_WATCHDOG_TIMER_REG),
  270. regmap_reg_range(AS3722_WATCHDOG_SOFTWARE_SIGNAL_REG,
  271. AS3722_BATTERY_VOLTAGE_MONITOR2_REG),
  272. regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_PWM_VCONTROL4_REG),
  273. regmap_reg_range(AS3722_BB_CHARGER_REG, AS3722_SRAM_REG),
  274. regmap_reg_range(AS3722_INTERRUPT_MASK1_REG, AS3722_TEMP_STATUS_REG),
  275. regmap_reg_range(AS3722_ADC0_CONTROL_REG, AS3722_ADC1_CONTROL_REG),
  276. regmap_reg_range(AS3722_ADC1_THRESHOLD_HI_MSB_REG,
  277. AS3722_ADC_CONFIGURATION_REG),
  278. regmap_reg_range(AS3722_LOCK_REG, AS3722_LOCK_REG),
  279. };
  280. static const struct regmap_access_table as3722_writable_table = {
  281. .yes_ranges = as3722_writable_ranges,
  282. .n_yes_ranges = ARRAY_SIZE(as3722_writable_ranges),
  283. };
  284. static const struct regmap_range as3722_cacheable_ranges[] = {
  285. regmap_reg_range(AS3722_SD0_VOLTAGE_REG, AS3722_LDO11_VOLTAGE_REG),
  286. regmap_reg_range(AS3722_SD_CONTROL_REG, AS3722_LDOCONTROL1_REG),
  287. };
  288. static const struct regmap_access_table as3722_volatile_table = {
  289. .no_ranges = as3722_cacheable_ranges,
  290. .n_no_ranges = ARRAY_SIZE(as3722_cacheable_ranges),
  291. };
  292. static const struct regmap_config as3722_regmap_config = {
  293. .reg_bits = 8,
  294. .val_bits = 8,
  295. .max_register = AS3722_MAX_REGISTER,
  296. .cache_type = REGCACHE_RBTREE,
  297. .rd_table = &as3722_readable_table,
  298. .wr_table = &as3722_writable_table,
  299. .volatile_table = &as3722_volatile_table,
  300. };
  301. static int as3722_i2c_of_probe(struct i2c_client *i2c,
  302. struct as3722 *as3722)
  303. {
  304. struct device_node *np = i2c->dev.of_node;
  305. struct irq_data *irq_data;
  306. if (!np) {
  307. dev_err(&i2c->dev, "Device Tree not found\n");
  308. return -EINVAL;
  309. }
  310. irq_data = irq_get_irq_data(i2c->irq);
  311. if (!irq_data) {
  312. dev_err(&i2c->dev, "Invalid IRQ: %d\n", i2c->irq);
  313. return -EINVAL;
  314. }
  315. as3722->en_intern_int_pullup = of_property_read_bool(np,
  316. "ams,enable-internal-int-pullup");
  317. as3722->en_intern_i2c_pullup = of_property_read_bool(np,
  318. "ams,enable-internal-i2c-pullup");
  319. as3722->irq_flags = irqd_get_trigger_type(irq_data);
  320. dev_dbg(&i2c->dev, "IRQ flags are 0x%08lx\n", as3722->irq_flags);
  321. return 0;
  322. }
  323. static int as3722_i2c_probe(struct i2c_client *i2c,
  324. const struct i2c_device_id *id)
  325. {
  326. struct as3722 *as3722;
  327. unsigned long irq_flags;
  328. int ret;
  329. as3722 = devm_kzalloc(&i2c->dev, sizeof(struct as3722), GFP_KERNEL);
  330. if (!as3722)
  331. return -ENOMEM;
  332. as3722->dev = &i2c->dev;
  333. as3722->chip_irq = i2c->irq;
  334. i2c_set_clientdata(i2c, as3722);
  335. ret = as3722_i2c_of_probe(i2c, as3722);
  336. if (ret < 0)
  337. return ret;
  338. as3722->regmap = devm_regmap_init_i2c(i2c, &as3722_regmap_config);
  339. if (IS_ERR(as3722->regmap)) {
  340. ret = PTR_ERR(as3722->regmap);
  341. dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
  342. return ret;
  343. }
  344. ret = as3722_check_device_id(as3722);
  345. if (ret < 0)
  346. return ret;
  347. irq_flags = as3722->irq_flags | IRQF_ONESHOT;
  348. ret = regmap_add_irq_chip(as3722->regmap, as3722->chip_irq,
  349. irq_flags, -1, &as3722_irq_chip,
  350. &as3722->irq_data);
  351. if (ret < 0) {
  352. dev_err(as3722->dev, "Failed to add regmap irq: %d\n", ret);
  353. return ret;
  354. }
  355. ret = as3722_configure_pullups(as3722);
  356. if (ret < 0)
  357. goto scrub;
  358. ret = mfd_add_devices(&i2c->dev, -1, as3722_devs,
  359. ARRAY_SIZE(as3722_devs), NULL, 0,
  360. regmap_irq_get_domain(as3722->irq_data));
  361. if (ret) {
  362. dev_err(as3722->dev, "Failed to add MFD devices: %d\n", ret);
  363. goto scrub;
  364. }
  365. dev_dbg(as3722->dev, "AS3722 core driver initialized successfully\n");
  366. return 0;
  367. scrub:
  368. regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data);
  369. return ret;
  370. }
  371. static int as3722_i2c_remove(struct i2c_client *i2c)
  372. {
  373. struct as3722 *as3722 = i2c_get_clientdata(i2c);
  374. mfd_remove_devices(as3722->dev);
  375. regmap_del_irq_chip(as3722->chip_irq, as3722->irq_data);
  376. return 0;
  377. }
  378. static const struct of_device_id as3722_of_match[] = {
  379. { .compatible = "ams,as3722", },
  380. {},
  381. };
  382. MODULE_DEVICE_TABLE(of, as3722_of_match);
  383. static const struct i2c_device_id as3722_i2c_id[] = {
  384. { "as3722", 0 },
  385. {},
  386. };
  387. MODULE_DEVICE_TABLE(i2c, as3722_i2c_id);
  388. static struct i2c_driver as3722_i2c_driver = {
  389. .driver = {
  390. .name = "as3722",
  391. .owner = THIS_MODULE,
  392. .of_match_table = as3722_of_match,
  393. },
  394. .probe = as3722_i2c_probe,
  395. .remove = as3722_i2c_remove,
  396. .id_table = as3722_i2c_id,
  397. };
  398. module_i2c_driver(as3722_i2c_driver);
  399. MODULE_DESCRIPTION("I2C support for AS3722 PMICs");
  400. MODULE_AUTHOR("Florian Lobmaier <florian.lobmaier@ams.com>");
  401. MODULE_AUTHOR("Laxman Dewangan <ldewangan@nvidia.com>");
  402. MODULE_LICENSE("GPL");