mfd: Add a data argument to the WM8350 IRQ free function
[safe/jmp/linux-2.6] / drivers / mfd / ab4500-core.c
1 /*
2  * Copyright (C) 2009 ST-Ericsson
3  *
4  * Author: Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com>
5  *
6  * This program is free software; you can redistribute it
7  * and/or modify it under the terms of the GNU General Public
8  * License version 2, as published by the Free Software Foundation.
9  *
10  * AB4500 is a companion power management chip used with U8500.
11  * On this platform, this is interfaced with SSP0 controller
12  * which is a ARM primecell pl022.
13  *
14  * At the moment the module just exports read/write features.
15  * Interrupt management to be added - TODO.
16  */
17 #include <linux/kernel.h>
18 #include <linux/init.h>
19 #include <linux/module.h>
20 #include <linux/platform_device.h>
21 #include <linux/spi/spi.h>
22 #include <linux/mfd/ab4500.h>
23
24 /* just required if probe fails, we need to
25  * unregister the device
26  */
27 static struct spi_driver ab4500_driver;
28
29 /*
30  * This funtion writes to any AB4500 registers using
31  * SPI protocol &  before it writes it packs the data
32  * in the below 24 bit frame format
33  *
34  *       *|------------------------------------|
35  *       *| 23|22...18|17.......10|9|8|7......0|
36  *       *| r/w  bank       adr          data  |
37  *       * ------------------------------------
38  *
39  * This function shouldn't be called from interrupt
40  * context
41  */
42 int ab4500_write(struct ab4500 *ab4500, unsigned char block,
43                 unsigned long addr, unsigned char data)
44 {
45         struct spi_transfer xfer;
46         struct spi_message      msg;
47         int err;
48         unsigned long spi_data =
49                 block << 18 | addr << 10 | data;
50
51         mutex_lock(&ab4500->lock);
52         ab4500->tx_buf[0] = spi_data;
53         ab4500->rx_buf[0] = 0;
54
55         xfer.tx_buf     = ab4500->tx_buf;
56         xfer.rx_buf     = NULL;
57         xfer.len        = sizeof(unsigned long);
58
59         spi_message_init(&msg);
60         spi_message_add_tail(&xfer, &msg);
61
62         err = spi_sync(ab4500->spi, &msg);
63         mutex_unlock(&ab4500->lock);
64
65         return err;
66 }
67 EXPORT_SYMBOL(ab4500_write);
68
69 int ab4500_read(struct ab4500 *ab4500, unsigned char block,
70                 unsigned long addr)
71 {
72         struct spi_transfer xfer;
73         struct spi_message      msg;
74         unsigned long spi_data =
75                 1 << 23 | block << 18 | addr << 10;
76
77         mutex_lock(&ab4500->lock);
78         ab4500->tx_buf[0] = spi_data;
79         ab4500->rx_buf[0] = 0;
80
81         xfer.tx_buf     = ab4500->tx_buf;
82         xfer.rx_buf     = ab4500->rx_buf;
83         xfer.len        = sizeof(unsigned long);
84
85         spi_message_init(&msg);
86         spi_message_add_tail(&xfer, &msg);
87
88         spi_sync(ab4500->spi, &msg);
89         mutex_unlock(&ab4500->lock);
90
91         return  ab4500->rx_buf[0];
92 }
93 EXPORT_SYMBOL(ab4500_read);
94
95 /* ref: ab3100 core */
96 #define AB4500_DEVICE(devname, devid)                           \
97 static struct platform_device ab4500_##devname##_device = {     \
98         .name   = devid,                                        \
99         .id     = -1,                                           \
100 }
101
102 /* list of childern devices of ab4500 - all are
103  * not populated here - TODO
104  */
105 AB4500_DEVICE(charger, "ab4500-charger");
106 AB4500_DEVICE(audio, "ab4500-audio");
107 AB4500_DEVICE(usb, "ab4500-usb");
108 AB4500_DEVICE(tvout, "ab4500-tvout");
109 AB4500_DEVICE(sim, "ab4500-sim");
110 AB4500_DEVICE(gpadc, "ab4500-gpadc");
111 AB4500_DEVICE(clkmgt, "ab4500-clkmgt");
112 AB4500_DEVICE(misc, "ab4500-misc");
113
114 static struct platform_device *ab4500_platform_devs[] = {
115         &ab4500_charger_device,
116         &ab4500_audio_device,
117         &ab4500_usb_device,
118         &ab4500_tvout_device,
119         &ab4500_sim_device,
120         &ab4500_gpadc_device,
121         &ab4500_clkmgt_device,
122         &ab4500_misc_device,
123 };
124
125 static int __init ab4500_probe(struct spi_device *spi)
126 {
127         struct ab4500   *ab4500;
128         unsigned char revision;
129         int err = 0;
130         int i;
131
132         ab4500 = kzalloc(sizeof *ab4500, GFP_KERNEL);
133         if (!ab4500) {
134                 dev_err(&spi->dev, "could not allocate AB4500\n");
135                 err = -ENOMEM;
136                 goto not_detect;
137         }
138
139         ab4500->spi = spi;
140         spi_set_drvdata(spi, ab4500);
141
142         mutex_init(&ab4500->lock);
143
144         /* read the revision register */
145         revision = ab4500_read(ab4500, AB4500_MISC, AB4500_REV_REG);
146
147         /* revision id 0x0 is for early drop, 0x10 is for cut1.0 */
148         if (revision == 0x0 || revision == 0x10)
149                 dev_info(&spi->dev, "Detected chip: %s, revision = %x\n",
150                         ab4500_driver.driver.name, revision);
151         else    {
152                 dev_err(&spi->dev, "unknown chip: 0x%x\n", revision);
153                 goto not_detect;
154         }
155
156         for (i = 0; i < ARRAY_SIZE(ab4500_platform_devs); i++)  {
157                 ab4500_platform_devs[i]->dev.parent =
158                         &spi->dev;
159                 platform_set_drvdata(ab4500_platform_devs[i], ab4500);
160         }
161
162         /* register the ab4500 platform devices */
163         platform_add_devices(ab4500_platform_devs,
164                         ARRAY_SIZE(ab4500_platform_devs));
165
166         return err;
167
168  not_detect:
169         spi_unregister_driver(&ab4500_driver);
170         kfree(ab4500);
171         return err;
172 }
173
174 static int __devexit ab4500_remove(struct spi_device *spi)
175 {
176         struct ab4500 *ab4500 =
177                 spi_get_drvdata(spi);
178
179         kfree(ab4500);
180
181         return 0;
182 }
183
184 static struct spi_driver ab4500_driver = {
185         .driver = {
186                 .name = "ab4500",
187                 .owner = THIS_MODULE,
188         },
189         .probe = ab4500_probe,
190         .remove = __devexit_p(ab4500_remove)
191 };
192
193 static int __devinit ab4500_init(void)
194 {
195         return spi_register_driver(&ab4500_driver);
196 }
197
198 static void __exit ab4500_exit(void)
199 {
200         spi_unregister_driver(&ab4500_driver);
201 }
202
203 subsys_initcall(ab4500_init);
204 module_exit(ab4500_exit);
205
206 MODULE_AUTHOR("Srinidhi KASAGAR <srinidhi.kasagar@stericsson.com");
207 MODULE_DESCRIPTION("AB4500 core driver");
208 MODULE_LICENSE("GPL");