]> bbs.cooldavid.org Git - net-next-2.6.git/blob - drivers/mfd/max8925-core.c
mfd: Initial max8925 support
[net-next-2.6.git] / drivers / mfd / max8925-core.c
1 /*
2  * Base driver for Maxim MAX8925
3  *
4  * Copyright (C) 2009 Marvell International Ltd.
5  *      Haojian Zhuang <haojian.zhuang@marvell.com>
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License version 2 as
9  * published by the Free Software Foundation.
10  */
11
12 #include <linux/kernel.h>
13 #include <linux/module.h>
14 #include <linux/i2c.h>
15 #include <linux/interrupt.h>
16 #include <linux/platform_device.h>
17 #include <linux/mfd/core.h>
18 #include <linux/mfd/max8925.h>
19
20 #define IRQ_MODE_STATUS         0
21 #define IRQ_MODE_MASK           1
22
23 static int __get_irq_offset(struct max8925_chip *chip, int irq, int mode,
24                             int *offset, int *bit)
25 {
26         if (!offset || !bit)
27                 return -EINVAL;
28
29         switch (chip->chip_id) {
30         case MAX8925_GPM:
31                 *bit = irq % BITS_PER_BYTE;
32                 if (irq < (BITS_PER_BYTE << 1)) {       /* irq = [0,15] */
33                         *offset = (mode) ? MAX8925_CHG_IRQ1_MASK
34                                 : MAX8925_CHG_IRQ1;
35                         if (irq >= BITS_PER_BYTE)
36                                 (*offset)++;
37                 } else {                                /* irq = [16,31] */
38                         *offset = (mode) ? MAX8925_ON_OFF_IRQ1_MASK
39                                 : MAX8925_ON_OFF_IRQ1;
40                         if (irq >= (BITS_PER_BYTE * 3))
41                                 (*offset)++;
42                 }
43                 break;
44         case MAX8925_ADC:
45                 *bit = irq % BITS_PER_BYTE;
46                 *offset = (mode) ? MAX8925_TSC_IRQ_MASK : MAX8925_TSC_IRQ;
47                 break;
48         default:
49                 goto out;
50         }
51         return 0;
52 out:
53         dev_err(chip->dev, "Wrong irq #%d is assigned\n", irq);
54         return -EINVAL;
55 }
56
57 static int __check_irq(int irq)
58 {
59         if ((irq < 0) || (irq >= MAX8925_NUM_IRQ))
60                 return -EINVAL;
61         return 0;
62 }
63
64 int max8925_mask_irq(struct max8925_chip *chip, int irq)
65 {
66         int offset, bit, ret;
67
68         ret = __get_irq_offset(chip, irq, IRQ_MODE_MASK, &offset, &bit);
69         if (ret < 0)
70                 return ret;
71         ret = max8925_set_bits(chip->i2c, offset, 1 << bit, 1 << bit);
72         return ret;
73 }
74
75 int max8925_unmask_irq(struct max8925_chip *chip, int irq)
76 {
77         int offset, bit, ret;
78
79         ret = __get_irq_offset(chip, irq, IRQ_MODE_MASK, &offset, &bit);
80         if (ret < 0)
81                 return ret;
82         ret = max8925_set_bits(chip->i2c, offset, 1 << bit, 0);
83         return ret;
84 }
85
86 #define INT_STATUS_NUM          (MAX8925_NUM_IRQ / BITS_PER_BYTE)
87
88 static irqreturn_t max8925_irq_thread(int irq, void *data)
89 {
90         struct max8925_chip *chip = data;
91         unsigned long irq_status[INT_STATUS_NUM];
92         unsigned char status_buf[INT_STATUS_NUM << 1];
93         int i, ret;
94
95         memset(irq_status, 0, sizeof(unsigned long) * INT_STATUS_NUM);
96
97         /* all these interrupt status registers are read-only */
98         switch (chip->chip_id) {
99         case MAX8925_GPM:
100                 ret = max8925_bulk_read(chip->i2c, MAX8925_CHG_IRQ1,
101                                         4, status_buf);
102                 if (ret < 0)
103                         goto out;
104                 ret = max8925_bulk_read(chip->i2c, MAX8925_ON_OFF_IRQ1,
105                                         2, &status_buf[4]);
106                 if (ret < 0)
107                         goto out;
108                 ret = max8925_bulk_read(chip->i2c, MAX8925_ON_OFF_IRQ2,
109                                         2, &status_buf[6]);
110                 if (ret < 0)
111                         goto out;
112                 /* clear masked interrupt status */
113                 status_buf[0] &= (~status_buf[2] & CHG_IRQ1_MASK);
114                 irq_status[0] |= status_buf[0];
115                 status_buf[1] &= (~status_buf[3] & CHG_IRQ2_MASK);
116                 irq_status[0] |= (status_buf[1] << BITS_PER_BYTE);
117                 status_buf[4] &= (~status_buf[5] & ON_OFF_IRQ1_MASK);
118                 irq_status[0] |= (status_buf[4] << (BITS_PER_BYTE * 2));
119                 status_buf[6] &= (~status_buf[7] & ON_OFF_IRQ2_MASK);
120                 irq_status[0] |= (status_buf[6] << (BITS_PER_BYTE * 3));
121                 break;
122         case MAX8925_ADC:
123                 ret = max8925_bulk_read(chip->i2c, MAX8925_TSC_IRQ,
124                                         2, status_buf);
125                 if (ret < 0)
126                         goto out;
127                 /* clear masked interrupt status */
128                 status_buf[0] &= (~status_buf[1] & TSC_IRQ_MASK);
129                 irq_status[0] |= status_buf[0];
130                 break;
131         default:
132                 goto out;
133         }
134
135         for_each_bit(i, &irq_status[0], MAX8925_NUM_IRQ) {
136                 clear_bit(i, irq_status);
137                 dev_dbg(chip->dev, "Servicing IRQ #%d in %s\n", i, chip->name);
138
139                 mutex_lock(&chip->irq_lock);
140                 if (chip->irq[i].handler)
141                         chip->irq[i].handler(i, chip->irq[i].data);
142                 else {
143                         max8925_mask_irq(chip, i);
144                         dev_err(chip->dev, "Noboday cares IRQ #%d in %s. "
145                                 "Now mask it.\n", i, chip->name);
146                 }
147                 mutex_unlock(&chip->irq_lock);
148         }
149 out:
150         return IRQ_HANDLED;
151 }
152
153 int max8925_request_irq(struct max8925_chip *chip, int irq,
154                         irq_handler_t handler, void *data)
155 {
156         if ((__check_irq(irq) < 0) || !handler)
157                 return -EINVAL;
158
159         mutex_lock(&chip->irq_lock);
160         chip->irq[irq].handler = handler;
161         chip->irq[irq].data = data;
162         mutex_unlock(&chip->irq_lock);
163         return 0;
164 }
165 EXPORT_SYMBOL(max8925_request_irq);
166
167 int max8925_free_irq(struct max8925_chip *chip, int irq)
168 {
169         if (__check_irq(irq) < 0)
170                 return -EINVAL;
171
172         mutex_lock(&chip->irq_lock);
173         chip->irq[irq].handler = NULL;
174         chip->irq[irq].data = NULL;
175         mutex_unlock(&chip->irq_lock);
176         return 0;
177 }
178 EXPORT_SYMBOL(max8925_free_irq);
179
180 static int __devinit device_gpm_init(struct max8925_chip *chip,
181                                       struct i2c_client *i2c,
182                                       struct max8925_platform_data *pdata)
183 {
184         int ret;
185
186         /* mask all IRQs */
187         ret = max8925_set_bits(i2c, MAX8925_CHG_IRQ1_MASK, 0x7, 0x7);
188         if (ret < 0)
189                 goto out;
190         ret = max8925_set_bits(i2c, MAX8925_CHG_IRQ2_MASK, 0xff, 0xff);
191         if (ret < 0)
192                 goto out;
193         ret = max8925_set_bits(i2c, MAX8925_ON_OFF_IRQ1_MASK, 0xff, 0xff);
194         if (ret < 0)
195                 goto out;
196         ret = max8925_set_bits(i2c, MAX8925_ON_OFF_IRQ2_MASK, 0x3, 0x3);
197         if (ret < 0)
198                 goto out;
199
200         chip->name = "GPM";
201         memset(chip->irq, 0, sizeof(struct max8925_irq) * MAX8925_NUM_IRQ);
202         ret = request_threaded_irq(i2c->irq, NULL, max8925_irq_thread,
203                                 IRQF_ONESHOT | IRQF_TRIGGER_LOW,
204                                 "max8925-gpm", chip);
205         if (ret < 0) {
206                 dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq);
207                 goto out;
208         }
209         chip->chip_irq = i2c->irq;
210
211         /* enable hard-reset for ONKEY power-off */
212         max8925_set_bits(i2c, MAX8925_SYSENSEL, 0x80, 0x80);
213 out:
214         return ret;
215 }
216
217 static int __devinit device_adc_init(struct max8925_chip *chip,
218                                      struct i2c_client *i2c,
219                                      struct max8925_platform_data *pdata)
220 {
221         int ret;
222
223         /* mask all IRQs */
224         ret = max8925_set_bits(i2c, MAX8925_TSC_IRQ_MASK, 3, 3);
225
226         chip->name = "ADC";
227         memset(chip->irq, 0, sizeof(struct max8925_irq) * MAX8925_NUM_IRQ);
228         ret = request_threaded_irq(i2c->irq, NULL, max8925_irq_thread,
229                                 IRQF_ONESHOT | IRQF_TRIGGER_LOW,
230                                 "max8925-adc", chip);
231         if (ret < 0) {
232                 dev_err(chip->dev, "Failed to request IRQ #%d.\n", i2c->irq);
233                 goto out;
234         }
235         chip->chip_irq = i2c->irq;
236 out:
237         return ret;
238 }
239
240 int __devinit max8925_device_init(struct max8925_chip *chip,
241                                   struct max8925_platform_data *pdata)
242 {
243         switch (chip->chip_id) {
244         case MAX8925_GPM:
245                 device_gpm_init(chip, chip->i2c, pdata);
246                 break;
247         case MAX8925_ADC:
248                 device_adc_init(chip, chip->i2c, pdata);
249                 break;
250         }
251         return 0;
252 }
253
254 void max8925_device_exit(struct max8925_chip *chip)
255 {
256         if (chip->chip_irq >= 0)
257                 free_irq(chip->chip_irq, chip);
258 }
259
260 MODULE_DESCRIPTION("PMIC Driver for Maxim MAX8925");
261 MODULE_AUTHOR("Haojian Zhuang <haojian.zhuang@marvell.com");
262 MODULE_LICENSE("GPL");