rc5t583-irq.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /*
  2. * Interrupt driver for RICOH583 power management chip.
  3. *
  4. * Copyright (c) 2011-2012, NVIDIA CORPORATION. All rights reserved.
  5. * Author: Laxman dewangan <ldewangan@nvidia.com>
  6. *
  7. * based on code
  8. * Copyright (C) 2011 RICOH COMPANY,LTD
  9. *
  10. * This program is free software; you can redistribute it and/or modify it
  11. * under the terms and conditions of the GNU General Public License,
  12. * version 2, as published by the Free Software Foundation.
  13. *
  14. * This program is distributed in the hope it will be useful, but WITHOUT
  15. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  16. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  17. * more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  21. *
  22. */
  23. #include <linux/interrupt.h>
  24. #include <linux/irq.h>
  25. #include <linux/i2c.h>
  26. #include <linux/mfd/rc5t583.h>
  27. enum int_type {
  28. SYS_INT = 0x1,
  29. DCDC_INT = 0x2,
  30. RTC_INT = 0x4,
  31. ADC_INT = 0x8,
  32. GPIO_INT = 0x10,
  33. };
  34. static int gpedge_add[] = {
  35. RC5T583_GPIO_GPEDGE2,
  36. RC5T583_GPIO_GPEDGE2
  37. };
  38. static int irq_en_add[] = {
  39. RC5T583_INT_EN_SYS1,
  40. RC5T583_INT_EN_SYS2,
  41. RC5T583_INT_EN_DCDC,
  42. RC5T583_INT_EN_RTC,
  43. RC5T583_INT_EN_ADC1,
  44. RC5T583_INT_EN_ADC2,
  45. RC5T583_INT_EN_ADC3,
  46. RC5T583_GPIO_EN_INT
  47. };
  48. static int irq_mon_add[] = {
  49. RC5T583_INT_MON_SYS1,
  50. RC5T583_INT_MON_SYS2,
  51. RC5T583_INT_MON_DCDC,
  52. RC5T583_INT_MON_RTC,
  53. RC5T583_INT_IR_ADCL,
  54. RC5T583_INT_IR_ADCH,
  55. RC5T583_INT_IR_ADCEND,
  56. RC5T583_INT_IR_GPIOF,
  57. RC5T583_INT_IR_GPIOR
  58. };
  59. static int irq_clr_add[] = {
  60. RC5T583_INT_IR_SYS1,
  61. RC5T583_INT_IR_SYS2,
  62. RC5T583_INT_IR_DCDC,
  63. RC5T583_INT_IR_RTC,
  64. RC5T583_INT_IR_ADCL,
  65. RC5T583_INT_IR_ADCH,
  66. RC5T583_INT_IR_ADCEND,
  67. RC5T583_INT_IR_GPIOF,
  68. RC5T583_INT_IR_GPIOR
  69. };
  70. static int main_int_type[] = {
  71. SYS_INT,
  72. SYS_INT,
  73. DCDC_INT,
  74. RTC_INT,
  75. ADC_INT,
  76. ADC_INT,
  77. ADC_INT,
  78. GPIO_INT,
  79. GPIO_INT,
  80. };
  81. struct rc5t583_irq_data {
  82. u8 int_type;
  83. u8 master_bit;
  84. u8 int_en_bit;
  85. u8 mask_reg_index;
  86. int grp_index;
  87. };
  88. #define RC5T583_IRQ(_int_type, _master_bit, _grp_index, \
  89. _int_bit, _mask_ind) \
  90. { \
  91. .int_type = _int_type, \
  92. .master_bit = _master_bit, \
  93. .grp_index = _grp_index, \
  94. .int_en_bit = _int_bit, \
  95. .mask_reg_index = _mask_ind, \
  96. }
  97. static const struct rc5t583_irq_data rc5t583_irqs[RC5T583_MAX_IRQS] = {
  98. [RC5T583_IRQ_ONKEY] = RC5T583_IRQ(SYS_INT, 0, 0, 0, 0),
  99. [RC5T583_IRQ_ACOK] = RC5T583_IRQ(SYS_INT, 0, 1, 1, 0),
  100. [RC5T583_IRQ_LIDOPEN] = RC5T583_IRQ(SYS_INT, 0, 2, 2, 0),
  101. [RC5T583_IRQ_PREOT] = RC5T583_IRQ(SYS_INT, 0, 3, 3, 0),
  102. [RC5T583_IRQ_CLKSTP] = RC5T583_IRQ(SYS_INT, 0, 4, 4, 0),
  103. [RC5T583_IRQ_ONKEY_OFF] = RC5T583_IRQ(SYS_INT, 0, 5, 5, 0),
  104. [RC5T583_IRQ_WD] = RC5T583_IRQ(SYS_INT, 0, 7, 7, 0),
  105. [RC5T583_IRQ_EN_PWRREQ1] = RC5T583_IRQ(SYS_INT, 0, 8, 0, 1),
  106. [RC5T583_IRQ_EN_PWRREQ2] = RC5T583_IRQ(SYS_INT, 0, 9, 1, 1),
  107. [RC5T583_IRQ_PRE_VINDET] = RC5T583_IRQ(SYS_INT, 0, 10, 2, 1),
  108. [RC5T583_IRQ_DC0LIM] = RC5T583_IRQ(DCDC_INT, 1, 0, 0, 2),
  109. [RC5T583_IRQ_DC1LIM] = RC5T583_IRQ(DCDC_INT, 1, 1, 1, 2),
  110. [RC5T583_IRQ_DC2LIM] = RC5T583_IRQ(DCDC_INT, 1, 2, 2, 2),
  111. [RC5T583_IRQ_DC3LIM] = RC5T583_IRQ(DCDC_INT, 1, 3, 3, 2),
  112. [RC5T583_IRQ_CTC] = RC5T583_IRQ(RTC_INT, 2, 0, 0, 3),
  113. [RC5T583_IRQ_YALE] = RC5T583_IRQ(RTC_INT, 2, 5, 5, 3),
  114. [RC5T583_IRQ_DALE] = RC5T583_IRQ(RTC_INT, 2, 6, 6, 3),
  115. [RC5T583_IRQ_WALE] = RC5T583_IRQ(RTC_INT, 2, 7, 7, 3),
  116. [RC5T583_IRQ_AIN1L] = RC5T583_IRQ(ADC_INT, 3, 0, 0, 4),
  117. [RC5T583_IRQ_AIN2L] = RC5T583_IRQ(ADC_INT, 3, 1, 1, 4),
  118. [RC5T583_IRQ_AIN3L] = RC5T583_IRQ(ADC_INT, 3, 2, 2, 4),
  119. [RC5T583_IRQ_VBATL] = RC5T583_IRQ(ADC_INT, 3, 3, 3, 4),
  120. [RC5T583_IRQ_VIN3L] = RC5T583_IRQ(ADC_INT, 3, 4, 4, 4),
  121. [RC5T583_IRQ_VIN8L] = RC5T583_IRQ(ADC_INT, 3, 5, 5, 4),
  122. [RC5T583_IRQ_AIN1H] = RC5T583_IRQ(ADC_INT, 3, 6, 0, 5),
  123. [RC5T583_IRQ_AIN2H] = RC5T583_IRQ(ADC_INT, 3, 7, 1, 5),
  124. [RC5T583_IRQ_AIN3H] = RC5T583_IRQ(ADC_INT, 3, 8, 2, 5),
  125. [RC5T583_IRQ_VBATH] = RC5T583_IRQ(ADC_INT, 3, 9, 3, 5),
  126. [RC5T583_IRQ_VIN3H] = RC5T583_IRQ(ADC_INT, 3, 10, 4, 5),
  127. [RC5T583_IRQ_VIN8H] = RC5T583_IRQ(ADC_INT, 3, 11, 5, 5),
  128. [RC5T583_IRQ_ADCEND] = RC5T583_IRQ(ADC_INT, 3, 12, 0, 6),
  129. [RC5T583_IRQ_GPIO0] = RC5T583_IRQ(GPIO_INT, 4, 0, 0, 7),
  130. [RC5T583_IRQ_GPIO1] = RC5T583_IRQ(GPIO_INT, 4, 1, 1, 7),
  131. [RC5T583_IRQ_GPIO2] = RC5T583_IRQ(GPIO_INT, 4, 2, 2, 7),
  132. [RC5T583_IRQ_GPIO3] = RC5T583_IRQ(GPIO_INT, 4, 3, 3, 7),
  133. [RC5T583_IRQ_GPIO4] = RC5T583_IRQ(GPIO_INT, 4, 4, 4, 7),
  134. [RC5T583_IRQ_GPIO5] = RC5T583_IRQ(GPIO_INT, 4, 5, 5, 7),
  135. [RC5T583_IRQ_GPIO6] = RC5T583_IRQ(GPIO_INT, 4, 6, 6, 7),
  136. [RC5T583_IRQ_GPIO7] = RC5T583_IRQ(GPIO_INT, 4, 7, 7, 7),
  137. };
  138. static void rc5t583_irq_lock(struct irq_data *irq_data)
  139. {
  140. struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
  141. mutex_lock(&rc5t583->irq_lock);
  142. }
  143. static void rc5t583_irq_unmask(struct irq_data *irq_data)
  144. {
  145. struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
  146. unsigned int __irq = irq_data->irq - rc5t583->irq_base;
  147. const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
  148. rc5t583->group_irq_en[data->grp_index] |= 1 << data->grp_index;
  149. rc5t583->intc_inten_reg |= 1 << data->master_bit;
  150. rc5t583->irq_en_reg[data->mask_reg_index] |= 1 << data->int_en_bit;
  151. }
  152. static void rc5t583_irq_mask(struct irq_data *irq_data)
  153. {
  154. struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
  155. unsigned int __irq = irq_data->irq - rc5t583->irq_base;
  156. const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
  157. rc5t583->group_irq_en[data->grp_index] &= ~(1 << data->grp_index);
  158. if (!rc5t583->group_irq_en[data->grp_index])
  159. rc5t583->intc_inten_reg &= ~(1 << data->master_bit);
  160. rc5t583->irq_en_reg[data->mask_reg_index] &= ~(1 << data->int_en_bit);
  161. }
  162. static int rc5t583_irq_set_type(struct irq_data *irq_data, unsigned int type)
  163. {
  164. struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
  165. unsigned int __irq = irq_data->irq - rc5t583->irq_base;
  166. const struct rc5t583_irq_data *data = &rc5t583_irqs[__irq];
  167. int val = 0;
  168. int gpedge_index;
  169. int gpedge_bit_pos;
  170. /* Supporting only trigger level inetrrupt */
  171. if ((data->int_type & GPIO_INT) && (type & IRQ_TYPE_EDGE_BOTH)) {
  172. gpedge_index = data->int_en_bit / 4;
  173. gpedge_bit_pos = data->int_en_bit % 4;
  174. if (type & IRQ_TYPE_EDGE_FALLING)
  175. val |= 0x2;
  176. if (type & IRQ_TYPE_EDGE_RISING)
  177. val |= 0x1;
  178. rc5t583->gpedge_reg[gpedge_index] &= ~(3 << gpedge_bit_pos);
  179. rc5t583->gpedge_reg[gpedge_index] |= (val << gpedge_bit_pos);
  180. rc5t583_irq_unmask(irq_data);
  181. return 0;
  182. }
  183. return -EINVAL;
  184. }
  185. static void rc5t583_irq_sync_unlock(struct irq_data *irq_data)
  186. {
  187. struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
  188. int i;
  189. int ret;
  190. for (i = 0; i < ARRAY_SIZE(rc5t583->gpedge_reg); i++) {
  191. ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
  192. rc5t583->gpedge_reg[i]);
  193. if (ret < 0)
  194. dev_warn(rc5t583->dev,
  195. "Error in writing reg 0x%02x error: %d\n",
  196. gpedge_add[i], ret);
  197. }
  198. for (i = 0; i < ARRAY_SIZE(rc5t583->irq_en_reg); i++) {
  199. ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
  200. rc5t583->irq_en_reg[i]);
  201. if (ret < 0)
  202. dev_warn(rc5t583->dev,
  203. "Error in writing reg 0x%02x error: %d\n",
  204. irq_en_add[i], ret);
  205. }
  206. ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN,
  207. rc5t583->intc_inten_reg);
  208. if (ret < 0)
  209. dev_warn(rc5t583->dev,
  210. "Error in writing reg 0x%02x error: %d\n",
  211. RC5T583_INTC_INTEN, ret);
  212. mutex_unlock(&rc5t583->irq_lock);
  213. }
  214. #ifdef CONFIG_PM_SLEEP
  215. static int rc5t583_irq_set_wake(struct irq_data *irq_data, unsigned int on)
  216. {
  217. struct rc5t583 *rc5t583 = irq_data_get_irq_chip_data(irq_data);
  218. return irq_set_irq_wake(rc5t583->chip_irq, on);
  219. }
  220. #else
  221. #define rc5t583_irq_set_wake NULL
  222. #endif
  223. static irqreturn_t rc5t583_irq(int irq, void *data)
  224. {
  225. struct rc5t583 *rc5t583 = data;
  226. uint8_t int_sts[RC5T583_MAX_INTERRUPT_MASK_REGS];
  227. uint8_t master_int = 0;
  228. int i;
  229. int ret;
  230. unsigned int rtc_int_sts = 0;
  231. /* Clear the status */
  232. for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++)
  233. int_sts[i] = 0;
  234. ret = rc5t583_read(rc5t583->dev, RC5T583_INTC_INTMON, &master_int);
  235. if (ret < 0) {
  236. dev_err(rc5t583->dev,
  237. "Error in reading reg 0x%02x error: %d\n",
  238. RC5T583_INTC_INTMON, ret);
  239. return IRQ_HANDLED;
  240. }
  241. for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; ++i) {
  242. if (!(master_int & main_int_type[i]))
  243. continue;
  244. ret = rc5t583_read(rc5t583->dev, irq_mon_add[i], &int_sts[i]);
  245. if (ret < 0) {
  246. dev_warn(rc5t583->dev,
  247. "Error in reading reg 0x%02x error: %d\n",
  248. irq_mon_add[i], ret);
  249. int_sts[i] = 0;
  250. continue;
  251. }
  252. if (main_int_type[i] & RTC_INT) {
  253. rtc_int_sts = 0;
  254. if (int_sts[i] & 0x1)
  255. rtc_int_sts |= BIT(6);
  256. if (int_sts[i] & 0x2)
  257. rtc_int_sts |= BIT(7);
  258. if (int_sts[i] & 0x4)
  259. rtc_int_sts |= BIT(0);
  260. if (int_sts[i] & 0x8)
  261. rtc_int_sts |= BIT(5);
  262. }
  263. ret = rc5t583_write(rc5t583->dev, irq_clr_add[i],
  264. ~int_sts[i]);
  265. if (ret < 0)
  266. dev_warn(rc5t583->dev,
  267. "Error in reading reg 0x%02x error: %d\n",
  268. irq_clr_add[i], ret);
  269. if (main_int_type[i] & RTC_INT)
  270. int_sts[i] = rtc_int_sts;
  271. }
  272. /* Merge gpio interrupts for rising and falling case*/
  273. int_sts[7] |= int_sts[8];
  274. /* Call interrupt handler if enabled */
  275. for (i = 0; i < RC5T583_MAX_IRQS; ++i) {
  276. const struct rc5t583_irq_data *data = &rc5t583_irqs[i];
  277. if ((int_sts[data->mask_reg_index] & (1 << data->int_en_bit)) &&
  278. (rc5t583->group_irq_en[data->master_bit] &
  279. (1 << data->grp_index)))
  280. handle_nested_irq(rc5t583->irq_base + i);
  281. }
  282. return IRQ_HANDLED;
  283. }
  284. static struct irq_chip rc5t583_irq_chip = {
  285. .name = "rc5t583-irq",
  286. .irq_mask = rc5t583_irq_mask,
  287. .irq_unmask = rc5t583_irq_unmask,
  288. .irq_bus_lock = rc5t583_irq_lock,
  289. .irq_bus_sync_unlock = rc5t583_irq_sync_unlock,
  290. .irq_set_type = rc5t583_irq_set_type,
  291. .irq_set_wake = rc5t583_irq_set_wake,
  292. };
  293. int rc5t583_irq_init(struct rc5t583 *rc5t583, int irq, int irq_base)
  294. {
  295. int i, ret;
  296. if (!irq_base) {
  297. dev_warn(rc5t583->dev, "No interrupt support on IRQ base\n");
  298. return -EINVAL;
  299. }
  300. mutex_init(&rc5t583->irq_lock);
  301. /* Initailize all int register to 0 */
  302. for (i = 0; i < RC5T583_MAX_INTERRUPT_EN_REGS; i++) {
  303. ret = rc5t583_write(rc5t583->dev, irq_en_add[i],
  304. rc5t583->irq_en_reg[i]);
  305. if (ret < 0)
  306. dev_warn(rc5t583->dev,
  307. "Error in writing reg 0x%02x error: %d\n",
  308. irq_en_add[i], ret);
  309. }
  310. for (i = 0; i < RC5T583_MAX_GPEDGE_REG; i++) {
  311. ret = rc5t583_write(rc5t583->dev, gpedge_add[i],
  312. rc5t583->gpedge_reg[i]);
  313. if (ret < 0)
  314. dev_warn(rc5t583->dev,
  315. "Error in writing reg 0x%02x error: %d\n",
  316. gpedge_add[i], ret);
  317. }
  318. ret = rc5t583_write(rc5t583->dev, RC5T583_INTC_INTEN, 0x0);
  319. if (ret < 0)
  320. dev_warn(rc5t583->dev,
  321. "Error in writing reg 0x%02x error: %d\n",
  322. RC5T583_INTC_INTEN, ret);
  323. /* Clear all interrupts in case they woke up active. */
  324. for (i = 0; i < RC5T583_MAX_INTERRUPT_MASK_REGS; i++) {
  325. ret = rc5t583_write(rc5t583->dev, irq_clr_add[i], 0);
  326. if (ret < 0)
  327. dev_warn(rc5t583->dev,
  328. "Error in writing reg 0x%02x error: %d\n",
  329. irq_clr_add[i], ret);
  330. }
  331. rc5t583->irq_base = irq_base;
  332. rc5t583->chip_irq = irq;
  333. for (i = 0; i < RC5T583_MAX_IRQS; i++) {
  334. int __irq = i + rc5t583->irq_base;
  335. irq_set_chip_data(__irq, rc5t583);
  336. irq_set_chip_and_handler(__irq, &rc5t583_irq_chip,
  337. handle_simple_irq);
  338. irq_set_nested_thread(__irq, 1);
  339. irq_clear_status_flags(__irq, IRQ_NOREQUEST);
  340. }
  341. ret = devm_request_threaded_irq(rc5t583->dev, irq, NULL, rc5t583_irq,
  342. IRQF_ONESHOT, "rc5t583", rc5t583);
  343. if (ret < 0)
  344. dev_err(rc5t583->dev,
  345. "Error in registering interrupt error: %d\n", ret);
  346. return ret;
  347. }