aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorQiao Zhou <zhouqiao@marvell.com>2012-07-09 02:37:32 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2012-07-09 09:12:51 -0400
commit70c6cce040661204986ebbf22224cb24bd77ea71 (patch)
treefe60851749c386e65735818e397850f2b3bd7d3e /drivers
parent49003a68926e073fc71062d210c6f9febc8665a2 (diff)
mfd: Support 88pm80x in 80x driver
88PM800 and 88PM805 are two discrete chips used for power management. Hardware designer can use them together or only one of them according to requirement. 88pm80x.c provides common i2c driver handling for both 800 and 805, such as i2c_driver init, regmap init, read/write api etc. 88pm800.c handles specifically for 800, such as chip init, irq init/handle, mfd device register, including rtc, onkey, regulator( to be add later) etc. besides that, 800 has three i2c device, one regular i2c client, two other i2c dummy for gpadc and power purpose. 88pm805.c handles specifically for 805, such as chip init, irq init/handle, mfd device register, including codec, headset/mic detect etc. the i2c operation of both 800 and 805 are via regmap, and 88pm80x-i2c exported a group of r/w bulk r/w and bits set API for facility. Signed-off-by: Qiao Zhou <zhouqiao@marvell.com> Reviewed-by: Arnd Bergmann <arnd@arndb.de> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mfd/88pm800.c593
-rw-r--r--drivers/mfd/88pm805.c299
-rw-r--r--drivers/mfd/88pm80x.c116
-rw-r--r--drivers/mfd/Kconfig24
-rw-r--r--drivers/mfd/Makefile2
5 files changed, 1034 insertions, 0 deletions
diff --git a/drivers/mfd/88pm800.c b/drivers/mfd/88pm800.c
new file mode 100644
index 000000000000..fe479ccfaa19
--- /dev/null
+++ b/drivers/mfd/88pm800.c
@@ -0,0 +1,593 @@
1/*
2 * Base driver for Marvell 88PM800
3 *
4 * Copyright (C) 2012 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
6 * Joseph(Yossi) Hanin <yhanin@marvell.com>
7 * Qiao Zhou <zhouqiao@marvell.com>
8 *
9 * This file is subject to the terms and conditions of the GNU General
10 * Public License. See the file "COPYING" in the main directory of this
11 * archive for more details.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/i2c.h>
26#include <linux/mfd/core.h>
27#include <linux/mfd/88pm80x.h>
28#include <linux/slab.h>
29
30#define PM800_CHIP_ID (0x00)
31
32/* Interrupt Registers */
33#define PM800_INT_STATUS1 (0x05)
34#define PM800_ONKEY_INT_STS1 (1 << 0)
35#define PM800_EXTON_INT_STS1 (1 << 1)
36#define PM800_CHG_INT_STS1 (1 << 2)
37#define PM800_BAT_INT_STS1 (1 << 3)
38#define PM800_RTC_INT_STS1 (1 << 4)
39#define PM800_CLASSD_OC_INT_STS1 (1 << 5)
40
41#define PM800_INT_STATUS2 (0x06)
42#define PM800_VBAT_INT_STS2 (1 << 0)
43#define PM800_VSYS_INT_STS2 (1 << 1)
44#define PM800_VCHG_INT_STS2 (1 << 2)
45#define PM800_TINT_INT_STS2 (1 << 3)
46#define PM800_GPADC0_INT_STS2 (1 << 4)
47#define PM800_TBAT_INT_STS2 (1 << 5)
48#define PM800_GPADC2_INT_STS2 (1 << 6)
49#define PM800_GPADC3_INT_STS2 (1 << 7)
50
51#define PM800_INT_STATUS3 (0x07)
52
53#define PM800_INT_STATUS4 (0x08)
54#define PM800_GPIO0_INT_STS4 (1 << 0)
55#define PM800_GPIO1_INT_STS4 (1 << 1)
56#define PM800_GPIO2_INT_STS4 (1 << 2)
57#define PM800_GPIO3_INT_STS4 (1 << 3)
58#define PM800_GPIO4_INT_STS4 (1 << 4)
59
60#define PM800_INT_ENA_1 (0x09)
61#define PM800_ONKEY_INT_ENA1 (1 << 0)
62#define PM800_EXTON_INT_ENA1 (1 << 1)
63#define PM800_CHG_INT_ENA1 (1 << 2)
64#define PM800_BAT_INT_ENA1 (1 << 3)
65#define PM800_RTC_INT_ENA1 (1 << 4)
66#define PM800_CLASSD_OC_INT_ENA1 (1 << 5)
67
68#define PM800_INT_ENA_2 (0x0A)
69#define PM800_VBAT_INT_ENA2 (1 << 0)
70#define PM800_VSYS_INT_ENA2 (1 << 1)
71#define PM800_VCHG_INT_ENA2 (1 << 2)
72#define PM800_TINT_INT_ENA2 (1 << 3)
73
74#define PM800_INT_ENA_3 (0x0B)
75#define PM800_GPADC0_INT_ENA3 (1 << 0)
76#define PM800_GPADC1_INT_ENA3 (1 << 1)
77#define PM800_GPADC2_INT_ENA3 (1 << 2)
78#define PM800_GPADC3_INT_ENA3 (1 << 3)
79#define PM800_GPADC4_INT_ENA3 (1 << 4)
80
81#define PM800_INT_ENA_4 (0x0C)
82#define PM800_GPIO0_INT_ENA4 (1 << 0)
83#define PM800_GPIO1_INT_ENA4 (1 << 1)
84#define PM800_GPIO2_INT_ENA4 (1 << 2)
85#define PM800_GPIO3_INT_ENA4 (1 << 3)
86#define PM800_GPIO4_INT_ENA4 (1 << 4)
87
88/* number of INT_ENA & INT_STATUS regs */
89#define PM800_INT_REG_NUM (4)
90
91/* Interrupt Number in 88PM800 */
92enum {
93 PM800_IRQ_ONKEY, /*EN1b0 *//*0 */
94 PM800_IRQ_EXTON, /*EN1b1 */
95 PM800_IRQ_CHG, /*EN1b2 */
96 PM800_IRQ_BAT, /*EN1b3 */
97 PM800_IRQ_RTC, /*EN1b4 */
98 PM800_IRQ_CLASSD, /*EN1b5 *//*5 */
99 PM800_IRQ_VBAT, /*EN2b0 */
100 PM800_IRQ_VSYS, /*EN2b1 */
101 PM800_IRQ_VCHG, /*EN2b2 */
102 PM800_IRQ_TINT, /*EN2b3 */
103 PM800_IRQ_GPADC0, /*EN3b0 *//*10 */
104 PM800_IRQ_GPADC1, /*EN3b1 */
105 PM800_IRQ_GPADC2, /*EN3b2 */
106 PM800_IRQ_GPADC3, /*EN3b3 */
107 PM800_IRQ_GPADC4, /*EN3b4 */
108 PM800_IRQ_GPIO0, /*EN4b0 *//*15 */
109 PM800_IRQ_GPIO1, /*EN4b1 */
110 PM800_IRQ_GPIO2, /*EN4b2 */
111 PM800_IRQ_GPIO3, /*EN4b3 */
112 PM800_IRQ_GPIO4, /*EN4b4 *//*19 */
113 PM800_MAX_IRQ,
114};
115
116enum {
117 /* Procida */
118 PM800_CHIP_A0 = 0x60,
119 PM800_CHIP_A1 = 0x61,
120 PM800_CHIP_B0 = 0x62,
121 PM800_CHIP_C0 = 0x63,
122 PM800_CHIP_END = PM800_CHIP_C0,
123
124 /* Make sure to update this to the last stepping */
125 PM8XXX_CHIP_END = PM800_CHIP_END
126};
127
128static const struct i2c_device_id pm80x_id_table[] = {
129 {"88PM800", CHIP_PM800},
130};
131MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
132
133static struct resource rtc_resources[] = {
134 {
135 .name = "88pm80x-rtc",
136 .start = PM800_IRQ_RTC,
137 .end = PM800_IRQ_RTC,
138 .flags = IORESOURCE_IRQ,
139 },
140};
141
142static struct mfd_cell rtc_devs[] = {
143 {
144 .name = "88pm80x-rtc",
145 .num_resources = ARRAY_SIZE(rtc_resources),
146 .resources = &rtc_resources[0],
147 .id = -1,
148 },
149};
150
151static struct resource onkey_resources[] = {
152 {
153 .name = "88pm80x-onkey",
154 .start = PM800_IRQ_ONKEY,
155 .end = PM800_IRQ_ONKEY,
156 .flags = IORESOURCE_IRQ,
157 },
158};
159
160static struct mfd_cell onkey_devs[] = {
161 {
162 .name = "88pm80x-onkey",
163 .num_resources = 1,
164 .resources = &onkey_resources[0],
165 .id = -1,
166 },
167};
168
169static const struct regmap_irq pm800_irqs[] = {
170 /* INT0 */
171 [PM800_IRQ_ONKEY] = {
172 .mask = PM800_ONKEY_INT_ENA1,
173 },
174 [PM800_IRQ_EXTON] = {
175 .mask = PM800_EXTON_INT_ENA1,
176 },
177 [PM800_IRQ_CHG] = {
178 .mask = PM800_CHG_INT_ENA1,
179 },
180 [PM800_IRQ_BAT] = {
181 .mask = PM800_BAT_INT_ENA1,
182 },
183 [PM800_IRQ_RTC] = {
184 .mask = PM800_RTC_INT_ENA1,
185 },
186 [PM800_IRQ_CLASSD] = {
187 .mask = PM800_CLASSD_OC_INT_ENA1,
188 },
189 /* INT1 */
190 [PM800_IRQ_VBAT] = {
191 .reg_offset = 1,
192 .mask = PM800_VBAT_INT_ENA2,
193 },
194 [PM800_IRQ_VSYS] = {
195 .reg_offset = 1,
196 .mask = PM800_VSYS_INT_ENA2,
197 },
198 [PM800_IRQ_VCHG] = {
199 .reg_offset = 1,
200 .mask = PM800_VCHG_INT_ENA2,
201 },
202 [PM800_IRQ_TINT] = {
203 .reg_offset = 1,
204 .mask = PM800_TINT_INT_ENA2,
205 },
206 /* INT2 */
207 [PM800_IRQ_GPADC0] = {
208 .reg_offset = 2,
209 .mask = PM800_GPADC0_INT_ENA3,
210 },
211 [PM800_IRQ_GPADC1] = {
212 .reg_offset = 2,
213 .mask = PM800_GPADC1_INT_ENA3,
214 },
215 [PM800_IRQ_GPADC2] = {
216 .reg_offset = 2,
217 .mask = PM800_GPADC2_INT_ENA3,
218 },
219 [PM800_IRQ_GPADC3] = {
220 .reg_offset = 2,
221 .mask = PM800_GPADC3_INT_ENA3,
222 },
223 [PM800_IRQ_GPADC4] = {
224 .reg_offset = 2,
225 .mask = PM800_GPADC4_INT_ENA3,
226 },
227 /* INT3 */
228 [PM800_IRQ_GPIO0] = {
229 .reg_offset = 3,
230 .mask = PM800_GPIO0_INT_ENA4,
231 },
232 [PM800_IRQ_GPIO1] = {
233 .reg_offset = 3,
234 .mask = PM800_GPIO1_INT_ENA4,
235 },
236 [PM800_IRQ_GPIO2] = {
237 .reg_offset = 3,
238 .mask = PM800_GPIO2_INT_ENA4,
239 },
240 [PM800_IRQ_GPIO3] = {
241 .reg_offset = 3,
242 .mask = PM800_GPIO3_INT_ENA4,
243 },
244 [PM800_IRQ_GPIO4] = {
245 .reg_offset = 3,
246 .mask = PM800_GPIO4_INT_ENA4,
247 },
248};
249
250static int __devinit device_gpadc_init(struct pm80x_chip *chip,
251 struct pm80x_platform_data *pdata)
252{
253 struct pm80x_subchip *subchip = chip->subchip;
254 struct regmap *map = subchip->regmap_gpadc;
255 int data = 0, mask = 0, ret = 0;
256
257 if (!map) {
258 dev_warn(chip->dev,
259 "Warning: gpadc regmap is not available!\n");
260 return -EINVAL;
261 }
262 /*
263 * initialize GPADC without activating it turn on GPADC
264 * measurments
265 */
266 ret = regmap_update_bits(map,
267 PM800_GPADC_MISC_CONFIG2,
268 PM800_GPADC_MISC_GPFSM_EN,
269 PM800_GPADC_MISC_GPFSM_EN);
270 if (ret < 0)
271 goto out;
272 /*
273 * This function configures the ADC as requires for
274 * CP implementation.CP does not "own" the ADC configuration
275 * registers and relies on AP.
276 * Reason: enable automatic ADC measurements needed
277 * for CP to get VBAT and RF temperature readings.
278 */
279 ret = regmap_update_bits(map, PM800_GPADC_MEAS_EN1,
280 PM800_MEAS_EN1_VBAT, PM800_MEAS_EN1_VBAT);
281 if (ret < 0)
282 goto out;
283 ret = regmap_update_bits(map, PM800_GPADC_MEAS_EN2,
284 (PM800_MEAS_EN2_RFTMP | PM800_MEAS_GP0_EN),
285 (PM800_MEAS_EN2_RFTMP | PM800_MEAS_GP0_EN));
286 if (ret < 0)
287 goto out;
288
289 /*
290 * the defult of PM800 is GPADC operates at 100Ks/s rate
291 * and Number of GPADC slots with active current bias prior
292 * to GPADC sampling = 1 slot for all GPADCs set for
293 * Temprature mesurmants
294 */
295 mask = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
296 PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
297
298 if (pdata && (pdata->batt_det == 0))
299 data = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN1 |
300 PM800_GPADC_GP_BIAS_EN2 | PM800_GPADC_GP_BIAS_EN3);
301 else
302 data = (PM800_GPADC_GP_BIAS_EN0 | PM800_GPADC_GP_BIAS_EN2 |
303 PM800_GPADC_GP_BIAS_EN3);
304
305 ret = regmap_update_bits(map, PM800_GP_BIAS_ENA1, mask, data);
306 if (ret < 0)
307 goto out;
308
309 dev_info(chip->dev, "pm800 device_gpadc_init: Done\n");
310 return 0;
311
312out:
313 dev_info(chip->dev, "pm800 device_gpadc_init: Failed!\n");
314 return ret;
315}
316
317static int __devinit device_irq_init_800(struct pm80x_chip *chip)
318{
319 struct regmap *map = chip->regmap;
320 unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
321 int data, mask, ret = -EINVAL;
322
323 if (!map || !chip->irq) {
324 dev_err(chip->dev, "incorrect parameters\n");
325 return -EINVAL;
326 }
327
328 /*
329 * irq_mode defines the way of clearing interrupt. it's read-clear by
330 * default.
331 */
332 mask =
333 PM800_WAKEUP2_INV_INT | PM800_WAKEUP2_INT_CLEAR |
334 PM800_WAKEUP2_INT_MASK;
335
336 data = PM800_WAKEUP2_INT_CLEAR;
337 ret = regmap_update_bits(map, PM800_WAKEUP2, mask, data);
338
339 if (ret < 0)
340 goto out;
341
342 ret =
343 regmap_add_irq_chip(chip->regmap, chip->irq, flags, -1,
344 chip->regmap_irq_chip, &chip->irq_data);
345
346out:
347 return ret;
348}
349
350static void device_irq_exit_800(struct pm80x_chip *chip)
351{
352 regmap_del_irq_chip(chip->irq, chip->irq_data);
353}
354
355static struct regmap_irq_chip pm800_irq_chip = {
356 .name = "88pm800",
357 .irqs = pm800_irqs,
358 .num_irqs = ARRAY_SIZE(pm800_irqs),
359
360 .num_regs = 4,
361 .status_base = PM800_INT_STATUS1,
362 .mask_base = PM800_INT_ENA_1,
363 .ack_base = PM800_INT_STATUS1,
364};
365
366static int pm800_pages_init(struct pm80x_chip *chip)
367{
368 struct pm80x_subchip *subchip;
369 struct i2c_client *client = chip->client;
370
371 subchip = chip->subchip;
372 /* PM800 block power: i2c addr 0x31 */
373 if (subchip->power_page_addr) {
374 subchip->power_page =
375 i2c_new_dummy(client->adapter, subchip->power_page_addr);
376 subchip->regmap_power =
377 devm_regmap_init_i2c(subchip->power_page,
378 &pm80x_regmap_config);
379 i2c_set_clientdata(subchip->power_page, chip);
380 } else
381 dev_info(chip->dev,
382 "PM800 block power 0x31: No power_page_addr\n");
383
384 /* PM800 block GPADC: i2c addr 0x32 */
385 if (subchip->gpadc_page_addr) {
386 subchip->gpadc_page = i2c_new_dummy(client->adapter,
387 subchip->gpadc_page_addr);
388 subchip->regmap_gpadc =
389 devm_regmap_init_i2c(subchip->gpadc_page,
390 &pm80x_regmap_config);
391 i2c_set_clientdata(subchip->gpadc_page, chip);
392 } else
393 dev_info(chip->dev,
394 "PM800 block GPADC 0x32: No gpadc_page_addr\n");
395
396 return 0;
397}
398
399static void pm800_pages_exit(struct pm80x_chip *chip)
400{
401 struct pm80x_subchip *subchip;
402
403 regmap_exit(chip->regmap);
404 i2c_unregister_device(chip->client);
405
406 subchip = chip->subchip;
407 if (subchip->power_page) {
408 regmap_exit(subchip->regmap_power);
409 i2c_unregister_device(subchip->power_page);
410 }
411 if (subchip->gpadc_page) {
412 regmap_exit(subchip->regmap_gpadc);
413 i2c_unregister_device(subchip->gpadc_page);
414 }
415}
416
417static int __devinit device_800_init(struct pm80x_chip *chip,
418 struct pm80x_platform_data *pdata)
419{
420 int ret, pmic_id;
421
422 regmap_read(chip->regmap, PM800_CHIP_ID, &ret);
423 if (ret < 0) {
424 dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
425 goto out;
426 }
427
428 pmic_id = ret & PM80X_VERSION_MASK;
429
430 if ((pmic_id >= PM800_CHIP_A0) && (pmic_id <= PM800_CHIP_END)) {
431 chip->version = ret;
432 dev_info(chip->dev,
433 "88PM80x:Marvell 88PM800 (ID:0x%x) detected\n", ret);
434 } else {
435 dev_err(chip->dev,
436 "Failed to detect Marvell 88PM800:ChipID[0x%x]\n", ret);
437 goto out;
438 }
439
440 /*
441 * alarm wake up bit will be clear in device_irq_init(),
442 * read before that
443 */
444 regmap_read(chip->regmap, PM800_RTC_CONTROL, &ret);
445 if (ret < 0) {
446 dev_err(chip->dev, "Failed to read RTC register: %d\n", ret);
447 goto out;
448 }
449 if (ret & PM800_ALARM_WAKEUP) {
450 if (pdata && pdata->rtc)
451 pdata->rtc->rtc_wakeup = 1;
452 }
453
454 ret = device_gpadc_init(chip, pdata);
455 if (ret < 0) {
456 dev_err(chip->dev, "[%s]Failed to init gpadc\n", __func__);
457 goto out;
458 }
459
460 chip->regmap_irq_chip = &pm800_irq_chip;
461
462 ret = device_irq_init_800(chip);
463 if (ret < 0) {
464 dev_err(chip->dev, "[%s]Failed to init pm800 irq\n", __func__);
465 goto out;
466 }
467
468 ret =
469 mfd_add_devices(chip->dev, 0, &onkey_devs[0],
470 ARRAY_SIZE(onkey_devs), &onkey_resources[0], 0);
471 if (ret < 0) {
472 dev_err(chip->dev, "Failed to add onkey subdev\n");
473 goto out_dev;
474 } else
475 dev_info(chip->dev, "[%s]:Added mfd onkey_devs\n", __func__);
476
477 if (pdata && pdata->rtc) {
478 rtc_devs[0].platform_data = pdata->rtc;
479 rtc_devs[0].pdata_size = sizeof(struct pm80x_rtc_pdata);
480 ret = mfd_add_devices(chip->dev, 0, &rtc_devs[0],
481 ARRAY_SIZE(rtc_devs), NULL, 0);
482 if (ret < 0) {
483 dev_err(chip->dev, "Failed to add rtc subdev\n");
484 goto out_dev;
485 } else
486 dev_info(chip->dev,
487 "[%s]:Added mfd rtc_devs\n", __func__);
488 }
489
490 return 0;
491out_dev:
492 mfd_remove_devices(chip->dev);
493 device_irq_exit_800(chip);
494out:
495 return ret;
496}
497
498static int __devinit pm800_probe(struct i2c_client *client,
499 const struct i2c_device_id *id)
500{
501 int ret = 0;
502 struct pm80x_chip *chip;
503 struct pm80x_platform_data *pdata = client->dev.platform_data;
504 struct pm80x_subchip *subchip;
505
506 ret = pm80x_init(client, id);
507 if (ret) {
508 dev_err(&client->dev, "pm800_init fail\n");
509 goto out_init;
510 }
511
512 chip = i2c_get_clientdata(client);
513
514 /* init subchip for PM800 */
515 subchip =
516 devm_kzalloc(&client->dev, sizeof(struct pm80x_subchip),
517 GFP_KERNEL);
518 if (!subchip) {
519 ret = -ENOMEM;
520 goto err_subchip_alloc;
521 }
522
523 subchip->power_page_addr = pdata->power_page_addr;
524 subchip->gpadc_page_addr = pdata->gpadc_page_addr;
525 chip->subchip = subchip;
526
527 ret = device_800_init(chip, pdata);
528 if (ret) {
529 dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
530 goto err_800_init;
531 }
532
533 ret = pm800_pages_init(chip);
534 if (ret) {
535 dev_err(&client->dev, "pm800_pages_init failed!\n");
536 goto err_page_init;
537 }
538
539 if (pdata->plat_config)
540 pdata->plat_config(chip, pdata);
541
542err_page_init:
543 mfd_remove_devices(chip->dev);
544 device_irq_exit_800(chip);
545err_800_init:
546 devm_kfree(&client->dev, subchip);
547err_subchip_alloc:
548 pm80x_deinit(client);
549out_init:
550 return ret;
551}
552
553static int __devexit pm800_remove(struct i2c_client *client)
554{
555 struct pm80x_chip *chip = i2c_get_clientdata(client);
556
557 mfd_remove_devices(chip->dev);
558 device_irq_exit_800(chip);
559
560 pm800_pages_exit(chip);
561 devm_kfree(&client->dev, chip->subchip);
562
563 pm80x_deinit(client);
564
565 return 0;
566}
567
568static struct i2c_driver pm800_driver = {
569 .driver = {
570 .name = "88PM80X",
571 .owner = THIS_MODULE,
572 .pm = &pm80x_pm_ops,
573 },
574 .probe = pm800_probe,
575 .remove = __devexit_p(pm800_remove),
576 .id_table = pm80x_id_table,
577};
578
579static int __init pm800_i2c_init(void)
580{
581 return i2c_add_driver(&pm800_driver);
582}
583subsys_initcall(pm800_i2c_init);
584
585static void __exit pm800_i2c_exit(void)
586{
587 i2c_del_driver(&pm800_driver);
588}
589module_exit(pm800_i2c_exit);
590
591MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM800");
592MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
593MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/88pm805.c b/drivers/mfd/88pm805.c
new file mode 100644
index 000000000000..d93c3091cb9f
--- /dev/null
+++ b/drivers/mfd/88pm805.c
@@ -0,0 +1,299 @@
1/*
2 * Base driver for Marvell 88PM805
3 *
4 * Copyright (C) 2012 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
6 * Joseph(Yossi) Hanin <yhanin@marvell.com>
7 * Qiao Zhou <zhouqiao@marvell.com>
8 *
9 * This file is subject to the terms and conditions of the GNU General
10 * Public License. See the file "COPYING" in the main directory of this
11 * archive for more details.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 */
22
23#include <linux/kernel.h>
24#include <linux/module.h>
25#include <linux/i2c.h>
26#include <linux/irq.h>
27#include <linux/mfd/core.h>
28#include <linux/mfd/88pm80x.h>
29#include <linux/slab.h>
30#include <linux/delay.h>
31
32#define PM805_CHIP_ID (0x00)
33
34static const struct i2c_device_id pm80x_id_table[] = {
35 {"88PM805", CHIP_PM805},
36};
37MODULE_DEVICE_TABLE(i2c, pm80x_id_table);
38
39/* Interrupt Number in 88PM805 */
40enum {
41 PM805_IRQ_LDO_OFF, /*0 */
42 PM805_IRQ_SRC_DPLL_LOCK, /*1 */
43 PM805_IRQ_CLIP_FAULT,
44 PM805_IRQ_MIC_CONFLICT,
45 PM805_IRQ_HP2_SHRT,
46 PM805_IRQ_HP1_SHRT, /*5 */
47 PM805_IRQ_FINE_PLL_FAULT,
48 PM805_IRQ_RAW_PLL_FAULT,
49 PM805_IRQ_VOLP_BTN_DET,
50 PM805_IRQ_VOLM_BTN_DET,
51 PM805_IRQ_SHRT_BTN_DET, /*10 */
52 PM805_IRQ_MIC_DET, /*11 */
53
54 PM805_MAX_IRQ,
55};
56
57static struct resource codec_resources[] = {
58 {
59 /* Headset microphone insertion or removal */
60 .name = "micin",
61 .start = PM805_IRQ_MIC_DET,
62 .end = PM805_IRQ_MIC_DET,
63 .flags = IORESOURCE_IRQ,
64 },
65 {
66 /* Audio short HP1 */
67 .name = "audio-short1",
68 .start = PM805_IRQ_HP1_SHRT,
69 .end = PM805_IRQ_HP1_SHRT,
70 .flags = IORESOURCE_IRQ,
71 },
72 {
73 /* Audio short HP2 */
74 .name = "audio-short2",
75 .start = PM805_IRQ_HP2_SHRT,
76 .end = PM805_IRQ_HP2_SHRT,
77 .flags = IORESOURCE_IRQ,
78 },
79};
80
81static struct mfd_cell codec_devs[] = {
82 {
83 .name = "88pm80x-codec",
84 .num_resources = ARRAY_SIZE(codec_resources),
85 .resources = &codec_resources[0],
86 .id = -1,
87 },
88};
89
90static struct regmap_irq pm805_irqs[] = {
91 /* INT0 */
92 [PM805_IRQ_LDO_OFF] = {
93 .mask = PM805_INT1_HP1_SHRT,
94 },
95 [PM805_IRQ_SRC_DPLL_LOCK] = {
96 .mask = PM805_INT1_HP2_SHRT,
97 },
98 [PM805_IRQ_CLIP_FAULT] = {
99 .mask = PM805_INT1_MIC_CONFLICT,
100 },
101 [PM805_IRQ_MIC_CONFLICT] = {
102 .mask = PM805_INT1_CLIP_FAULT,
103 },
104 [PM805_IRQ_HP2_SHRT] = {
105 .mask = PM805_INT1_LDO_OFF,
106 },
107 [PM805_IRQ_HP1_SHRT] = {
108 .mask = PM805_INT1_SRC_DPLL_LOCK,
109 },
110 /* INT1 */
111 [PM805_IRQ_FINE_PLL_FAULT] = {
112 .reg_offset = 1,
113 .mask = PM805_INT2_MIC_DET,
114 },
115 [PM805_IRQ_RAW_PLL_FAULT] = {
116 .reg_offset = 1,
117 .mask = PM805_INT2_SHRT_BTN_DET,
118 },
119 [PM805_IRQ_VOLP_BTN_DET] = {
120 .reg_offset = 1,
121 .mask = PM805_INT2_VOLM_BTN_DET,
122 },
123 [PM805_IRQ_VOLM_BTN_DET] = {
124 .reg_offset = 1,
125 .mask = PM805_INT2_VOLP_BTN_DET,
126 },
127 [PM805_IRQ_SHRT_BTN_DET] = {
128 .reg_offset = 1,
129 .mask = PM805_INT2_RAW_PLL_FAULT,
130 },
131 [PM805_IRQ_MIC_DET] = {
132 .reg_offset = 1,
133 .mask = PM805_INT2_FINE_PLL_FAULT,
134 },
135};
136
137static int __devinit device_irq_init_805(struct pm80x_chip *chip)
138{
139 struct regmap *map = chip->regmap;
140 unsigned long flags = IRQF_TRIGGER_FALLING | IRQF_ONESHOT;
141 int data, mask, ret = -EINVAL;
142
143 if (!map || !chip->irq) {
144 dev_err(chip->dev, "incorrect parameters\n");
145 return -EINVAL;
146 }
147
148 /*
149 * irq_mode defines the way of clearing interrupt. it's read-clear by
150 * default.
151 */
152 mask =
153 PM805_STATUS0_INT_CLEAR | PM805_STATUS0_INV_INT |
154 PM800_STATUS0_INT_MASK;
155
156 data = PM805_STATUS0_INT_CLEAR;
157 ret = regmap_update_bits(map, PM805_INT_STATUS0, mask, data);
158 /*
159 * PM805_INT_STATUS is under 32K clock domain, so need to
160 * add proper delay before the next I2C register access.
161 */
162 msleep(1);
163
164 if (ret < 0)
165 goto out;
166
167 ret =
168 regmap_add_irq_chip(chip->regmap, chip->irq, flags, -1,
169 chip->regmap_irq_chip, &chip->irq_data);
170
171out:
172 return ret;
173}
174
175static void device_irq_exit_805(struct pm80x_chip *chip)
176{
177 regmap_del_irq_chip(chip->irq, chip->irq_data);
178}
179
180static struct regmap_irq_chip pm805_irq_chip = {
181 .name = "88pm805",
182 .irqs = pm805_irqs,
183 .num_irqs = ARRAY_SIZE(pm805_irqs),
184
185 .num_regs = 2,
186 .status_base = PM805_INT_STATUS1,
187 .mask_base = PM805_INT_MASK1,
188 .ack_base = PM805_INT_STATUS1,
189};
190
191static int __devinit device_805_init(struct pm80x_chip *chip)
192{
193 int ret = 0;
194 struct regmap *map = chip->regmap;
195
196 if (!map) {
197 dev_err(chip->dev, "regmap is invalid\n");
198 return -EINVAL;
199 }
200
201 regmap_read(map, PM805_CHIP_ID, &ret);
202 if (ret < 0) {
203 dev_err(chip->dev, "Failed to read CHIP ID: %d\n", ret);
204 goto out_irq_init;
205 }
206 chip->version = ret;
207
208 chip->regmap_irq_chip = &pm805_irq_chip;
209
210 ret = device_irq_init_805(chip);
211 if (ret < 0) {
212 dev_err(chip->dev, "Failed to init pm805 irq!\n");
213 goto out_irq_init;
214 }
215
216 ret = mfd_add_devices(chip->dev, 0, &codec_devs[0],
217 ARRAY_SIZE(codec_devs), &codec_resources[0], 0);
218 if (ret < 0) {
219 dev_err(chip->dev, "Failed to add codec subdev\n");
220 goto out_codec;
221 } else
222 dev_info(chip->dev, "[%s]:Added mfd codec_devs\n", __func__);
223
224 return 0;
225
226out_codec:
227 device_irq_exit_805(chip);
228out_irq_init:
229 return ret;
230}
231
232static int __devinit pm805_probe(struct i2c_client *client,
233 const struct i2c_device_id *id)
234{
235 int ret = 0;
236 struct pm80x_chip *chip;
237 struct pm80x_platform_data *pdata = client->dev.platform_data;
238
239 ret = pm80x_init(client, id);
240 if (ret) {
241 dev_err(&client->dev, "pm805_init fail!\n");
242 goto out_init;
243 }
244
245 chip = i2c_get_clientdata(client);
246
247 ret = device_805_init(chip);
248 if (ret) {
249 dev_err(chip->dev, "%s id 0x%x failed!\n", __func__, chip->id);
250 goto err_805_init;
251 }
252
253 if (pdata->plat_config)
254 pdata->plat_config(chip, pdata);
255
256err_805_init:
257 pm80x_deinit(client);
258out_init:
259 return ret;
260}
261
262static int __devexit pm805_remove(struct i2c_client *client)
263{
264 struct pm80x_chip *chip = i2c_get_clientdata(client);
265
266 mfd_remove_devices(chip->dev);
267 device_irq_exit_805(chip);
268
269 pm80x_deinit(client);
270
271 return 0;
272}
273
274static struct i2c_driver pm805_driver = {
275 .driver = {
276 .name = "88PM80X",
277 .owner = THIS_MODULE,
278 .pm = &pm80x_pm_ops,
279 },
280 .probe = pm805_probe,
281 .remove = __devexit_p(pm805_remove),
282 .id_table = pm80x_id_table,
283};
284
285static int __init pm805_i2c_init(void)
286{
287 return i2c_add_driver(&pm805_driver);
288}
289subsys_initcall(pm805_i2c_init);
290
291static void __exit pm805_i2c_exit(void)
292{
293 i2c_del_driver(&pm805_driver);
294}
295module_exit(pm805_i2c_exit);
296
297MODULE_DESCRIPTION("PMIC Driver for Marvell 88PM805");
298MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
299MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/88pm80x.c b/drivers/mfd/88pm80x.c
new file mode 100644
index 000000000000..90aa18a37f79
--- /dev/null
+++ b/drivers/mfd/88pm80x.c
@@ -0,0 +1,116 @@
1/*
2 * I2C driver for Marvell 88PM80x
3 *
4 * Copyright (C) 2012 Marvell International Ltd.
5 * Haojian Zhuang <haojian.zhuang@marvell.com>
6 * Joseph(Yossi) Hanin <yhanin@marvell.com>
7 * Qiao Zhou <zhouqiao@marvell.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13#include <linux/kernel.h>
14#include <linux/module.h>
15#include <linux/i2c.h>
16#include <linux/mfd/88pm80x.h>
17#include <linux/slab.h>
18#include <linux/uaccess.h>
19#include <linux/err.h>
20
21
22const struct regmap_config pm80x_regmap_config = {
23 .reg_bits = 8,
24 .val_bits = 8,
25};
26
27int __devinit pm80x_init(struct i2c_client *client,
28 const struct i2c_device_id *id)
29{
30 struct pm80x_chip *chip;
31 struct regmap *map;
32 int ret = 0;
33
34 chip =
35 devm_kzalloc(&client->dev, sizeof(struct pm80x_chip), GFP_KERNEL);
36 if (!chip)
37 return -ENOMEM;
38
39 map = devm_regmap_init_i2c(client, &pm80x_regmap_config);
40 if (IS_ERR(map)) {
41 ret = PTR_ERR(map);
42 dev_err(&client->dev, "Failed to allocate register map: %d\n",
43 ret);
44 goto err_regmap_init;
45 }
46
47 chip->id = id->driver_data;
48 if (chip->id < CHIP_PM800 || chip->id > CHIP_PM805) {
49 ret = -EINVAL;
50 goto err_chip_id;
51 }
52
53 chip->client = client;
54 chip->regmap = map;
55
56 chip->irq = client->irq;
57
58 chip->dev = &client->dev;
59 dev_set_drvdata(chip->dev, chip);
60 i2c_set_clientdata(chip->client, chip);
61
62 device_init_wakeup(&client->dev, 1);
63
64 return 0;
65
66err_chip_id:
67 regmap_exit(map);
68err_regmap_init:
69 devm_kfree(&client->dev, chip);
70 return ret;
71}
72EXPORT_SYMBOL_GPL(pm80x_init);
73
74int __devexit pm80x_deinit(struct i2c_client *client)
75{
76 struct pm80x_chip *chip = i2c_get_clientdata(client);
77
78 regmap_exit(chip->regmap);
79 devm_kfree(&client->dev, chip);
80
81 return 0;
82}
83EXPORT_SYMBOL_GPL(pm80x_deinit);
84
85#ifdef CONFIG_PM_SLEEP
86static int pm80x_suspend(struct device *dev)
87{
88 struct i2c_client *client = container_of(dev, struct i2c_client, dev);
89 struct pm80x_chip *chip = i2c_get_clientdata(client);
90
91 if (chip && chip->wu_flag)
92 if (device_may_wakeup(chip->dev))
93 enable_irq_wake(chip->irq);
94
95 return 0;
96}
97
98static int pm80x_resume(struct device *dev)
99{
100 struct i2c_client *client = container_of(dev, struct i2c_client, dev);
101 struct pm80x_chip *chip = i2c_get_clientdata(client);
102
103 if (chip && chip->wu_flag)
104 if (device_may_wakeup(chip->dev))
105 disable_irq_wake(chip->irq);
106
107 return 0;
108}
109#endif
110
111SIMPLE_DEV_PM_OPS(pm80x_pm_ops, pm80x_suspend, pm80x_resume);
112EXPORT_SYMBOL_GPL(pm80x_pm_ops);
113
114MODULE_DESCRIPTION("I2C Driver for Marvell 88PM80x");
115MODULE_AUTHOR("Qiao Zhou <zhouqiao@marvell.com>");
116MODULE_LICENSE("GPL");
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 5c043693f52c..9c3ab2ab7dc7 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -21,6 +21,30 @@ config MFD_88PM860X
21 select individual components like voltage regulators, RTC and 21 select individual components like voltage regulators, RTC and
22 battery-charger under the corresponding menus. 22 battery-charger under the corresponding menus.
23 23
24config MFD_88PM800
25 tristate "Support Marvell 88PM800"
26 depends on I2C=y && GENERIC_HARDIRQS
27 select REGMAP_I2C
28 select REGMAP_IRQ
29 select MFD_CORE
30 help
31 This supports for Marvell 88PM800 Power Management IC.
32 This includes the I2C driver and the core APIs _only_, you have to
33 select individual components like voltage regulators, RTC and
34 battery-charger under the corresponding menus.
35
36config MFD_88PM805
37 tristate "Support Marvell 88PM805"
38 depends on I2C=y && GENERIC_HARDIRQS
39 select REGMAP_I2C
40 select REGMAP_IRQ
41 select MFD_CORE
42 help
43 This supports for Marvell 88PM805 Power Management IC. This includes
44 the I2C driver and the core APIs _only_, you have to select individual
45 components like codec device, headset/Mic device under the
46 corresponding menus.
47
24config MFD_SM501 48config MFD_SM501
25 tristate "Support for Silicon Motion SM501" 49 tristate "Support for Silicon Motion SM501"
26 ---help--- 50 ---help---
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index f28885bb103c..09674a99eb60 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -4,6 +4,8 @@
4 4
588pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o 588pm860x-objs := 88pm860x-core.o 88pm860x-i2c.o
6obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o 6obj-$(CONFIG_MFD_88PM860X) += 88pm860x.o
7obj-$(CONFIG_MFD_88PM800) += 88pm800.o 88pm80x.o
8obj-$(CONFIG_MFD_88PM805) += 88pm805.o 88pm80x.o
7obj-$(CONFIG_MFD_SM501) += sm501.o 9obj-$(CONFIG_MFD_SM501) += sm501.o
8obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o 10obj-$(CONFIG_MFD_ASIC3) += asic3.o tmio_core.o
9 11