rc5t583-irq.c 12 KB

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