blob: ed297856a9bdac22a7d3641d8e7baccd40f0cd17 [file] [log] [blame]
Jay Chokshi24fc9b62011-07-18 10:51:05 -07001/*
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 and
6 * only version 2 as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14#define pr_fmt(fmt) "%s: " fmt, __func__
15
16#include <linux/kernel.h>
17#include <linux/platform_device.h>
18#include <linux/slab.h>
19#include <linux/err.h>
20#include <linux/msm_ssbi.h>
21#include <linux/mfd/core.h>
22#include <linux/mfd/pm8xxx/pm8821.h>
23#include <linux/mfd/pm8xxx/core.h>
24
25#define REG_HWREV 0x002 /* PMIC4 revision */
26#define REG_HWREV_2 0x0E8 /* PMIC4 revision 2 */
27
28#define REG_MPP_BASE 0x050
29
30#define PM8821_VERSION_MASK 0xFFF0
31#define PM8821_VERSION_VALUE 0x07F0
32#define PM8821_REVISION_MASK 0x000F
33
34#define SINGLE_IRQ_RESOURCE(_name, _irq) \
35{ \
36 .name = _name, \
37 .start = _irq, \
38 .end = _irq, \
39 .flags = IORESOURCE_IRQ, \
40}
41
42struct pm8821 {
43 struct device *dev;
44 struct pm_irq_chip *irq_chip;
45 u32 rev_registers;
46};
47
48static int pm8821_readb(const struct device *dev, u16 addr, u8 *val)
49{
50 const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
51 const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
52
53 return msm_ssbi_read(pmic->dev->parent, addr, val, 1);
54}
55
56static int pm8821_writeb(const struct device *dev, u16 addr, u8 val)
57{
58 const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
59 const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
60
61 return msm_ssbi_write(pmic->dev->parent, addr, &val, 1);
62}
63
64static int pm8821_read_buf(const struct device *dev, u16 addr, u8 *buf,
65 int cnt)
66{
67 const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
68 const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
69
70 return msm_ssbi_read(pmic->dev->parent, addr, buf, cnt);
71}
72
73static int pm8821_write_buf(const struct device *dev, u16 addr, u8 *buf,
74 int cnt)
75{
76 const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
77 const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
78
79 return msm_ssbi_write(pmic->dev->parent, addr, buf, cnt);
80}
81
82static int pm8821_read_irq_stat(const struct device *dev, int irq)
83{
84 const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
85 const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
86
87 return pm8xxx_get_irq_stat(pmic->irq_chip, irq);
88}
89
90static enum pm8xxx_version pm8821_get_version(const struct device *dev)
91{
92 const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
93 const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
94 enum pm8xxx_version version = -ENODEV;
95
96 if ((pmic->rev_registers & PM8821_VERSION_MASK) == PM8821_VERSION_VALUE)
97 version = PM8XXX_VERSION_8821;
98
99 return version;
100}
101
102static int pm8821_get_revision(const struct device *dev)
103{
104 const struct pm8xxx_drvdata *pm8821_drvdata = dev_get_drvdata(dev);
105 const struct pm8821 *pmic = pm8821_drvdata->pm_chip_data;
106
107 return pmic->rev_registers & PM8821_REVISION_MASK;
108}
109
110static struct pm8xxx_drvdata pm8821_drvdata = {
111 .pmic_readb = pm8821_readb,
112 .pmic_writeb = pm8821_writeb,
113 .pmic_read_buf = pm8821_read_buf,
114 .pmic_write_buf = pm8821_write_buf,
115 .pmic_read_irq_stat = pm8821_read_irq_stat,
116 .pmic_get_version = pm8821_get_version,
117 .pmic_get_revision = pm8821_get_revision,
118};
119
120static const struct resource mpp_cell_resources[] __devinitconst = {
121 {
122 .start = PM8821_IRQ_BLOCK_BIT(PM8821_MPP_BLOCK_START, 0),
123 .end = PM8821_IRQ_BLOCK_BIT(PM8821_MPP_BLOCK_START, 0)
124 + PM8821_NR_MPPS - 1,
125 .flags = IORESOURCE_IRQ,
126 },
127};
128
129static struct mfd_cell mpp_cell __devinitdata = {
130 .name = PM8XXX_MPP_DEV_NAME,
131 .id = 1,
132 .resources = mpp_cell_resources,
133 .num_resources = ARRAY_SIZE(mpp_cell_resources),
134};
135
136static struct mfd_cell debugfs_cell __devinitdata = {
137 .name = "pm8xxx-debug",
138 .id = 1,
139 .platform_data = "pm8821-dbg",
Jay Chokshi520d4732011-10-11 12:22:02 -0700140 .pdata_size = sizeof("pm8821-dbg"),
Jay Chokshi24fc9b62011-07-18 10:51:05 -0700141};
142
143
144static int __devinit
145pm8821_add_subdevices(const struct pm8821_platform_data *pdata,
146 struct pm8821 *pmic)
147{
148 int ret = 0, irq_base = 0;
149 struct pm_irq_chip *irq_chip;
150
151 if (pdata->irq_pdata) {
152 pdata->irq_pdata->irq_cdata.nirqs = PM8821_NR_IRQS;
153 irq_base = pdata->irq_pdata->irq_base;
154 irq_chip = pm8xxx_irq_init(pmic->dev, pdata->irq_pdata);
155
156 if (IS_ERR(irq_chip)) {
157 pr_err("Failed to init interrupts ret=%ld\n",
158 PTR_ERR(irq_chip));
159 return PTR_ERR(irq_chip);
160 }
161 pmic->irq_chip = irq_chip;
162 }
163
164 if (pdata->mpp_pdata) {
165 pdata->mpp_pdata->core_data.nmpps = PM8821_NR_MPPS;
166 pdata->mpp_pdata->core_data.base_addr = REG_MPP_BASE;
167 mpp_cell.platform_data = pdata->mpp_pdata;
Jay Chokshi520d4732011-10-11 12:22:02 -0700168 mpp_cell.pdata_size = sizeof(struct pm8xxx_mpp_platform_data);
Jay Chokshi24fc9b62011-07-18 10:51:05 -0700169 ret = mfd_add_devices(pmic->dev, 0, &mpp_cell, 1, NULL,
170 irq_base);
171 if (ret) {
172 pr_err("Failed to add mpp subdevice ret=%d\n", ret);
173 goto bail;
174 }
175 }
176
177 ret = mfd_add_devices(pmic->dev, 0, &debugfs_cell, 1, NULL, irq_base);
178 if (ret) {
179 pr_err("Failed to add debugfs subdevice ret=%d\n", ret);
180 goto bail;
181 }
182
183 return 0;
184bail:
185 if (pmic->irq_chip) {
186 pm8xxx_irq_exit(pmic->irq_chip);
187 pmic->irq_chip = NULL;
188 }
189 return ret;
190}
191
192static const char * const pm8821_rev_names[] = {
193 [PM8XXX_REVISION_8821_TEST] = "test",
194 [PM8XXX_REVISION_8821_1p0] = "1.0",
195 [PM8XXX_REVISION_8821_2p0] = "2.0",
196 [PM8XXX_REVISION_8821_2p1] = "2.1",
197};
198
199static int __devinit pm8821_probe(struct platform_device *pdev)
200{
201 const struct pm8821_platform_data *pdata = pdev->dev.platform_data;
202 const char *revision_name = "unknown";
203 struct pm8821 *pmic;
204 enum pm8xxx_version version;
205 int revision;
206 int rc;
207 u8 val;
208
209 if (!pdata) {
210 pr_err("missing platform data\n");
211 return -EINVAL;
212 }
213
214 pmic = kzalloc(sizeof(struct pm8821), GFP_KERNEL);
215 if (!pmic) {
216 pr_err("Cannot alloc pm8821 struct\n");
217 return -ENOMEM;
218 }
219
220 /* Read PMIC chip revision */
221 rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV, &val, sizeof(val));
222 if (rc) {
223 pr_err("Failed to read hw rev reg %d:rc=%d\n", REG_HWREV, rc);
224 goto err_read_rev;
225 }
226 pr_info("PMIC revision 1: PM8821 rev %02X\n", val);
227 pmic->rev_registers = val;
228
229 /* Read PMIC chip revision 2 */
230 rc = msm_ssbi_read(pdev->dev.parent, REG_HWREV_2, &val, sizeof(val));
231 if (rc) {
232 pr_err("Failed to read hw rev 2 reg %d:rc=%d\n",
233 REG_HWREV_2, rc);
234 goto err_read_rev;
235 }
236 pr_info("PMIC revision 2: PM8821 rev %02X\n", val);
237 pmic->rev_registers |= val << BITS_PER_BYTE;
238
239 pmic->dev = &pdev->dev;
240 pm8821_drvdata.pm_chip_data = pmic;
241 platform_set_drvdata(pdev, &pm8821_drvdata);
242
243 /* Print out human readable version and revision names. */
244 version = pm8xxx_get_version(pmic->dev);
245 if (version == PM8XXX_VERSION_8821) {
246 revision = pm8xxx_get_revision(pmic->dev);
247 if (revision >= 0 && revision < ARRAY_SIZE(pm8821_rev_names))
248 revision_name = pm8821_rev_names[revision];
249 pr_info("PMIC version: PM8821 ver %s\n", revision_name);
250 } else {
251 WARN_ON(version != PM8XXX_VERSION_8821);
252 }
253
254 rc = pm8821_add_subdevices(pdata, pmic);
255 if (rc) {
256 pr_err("Cannot add subdevices rc=%d\n", rc);
257 goto err;
258 }
259
260 return 0;
261
262err:
263 mfd_remove_devices(pmic->dev);
264 platform_set_drvdata(pdev, NULL);
265err_read_rev:
266 kfree(pmic);
267 return rc;
268}
269
270static int __devexit pm8821_remove(struct platform_device *pdev)
271{
272 struct pm8xxx_drvdata *drvdata;
273 struct pm8821 *pmic = NULL;
274
275 drvdata = platform_get_drvdata(pdev);
276 if (drvdata)
277 pmic = drvdata->pm_chip_data;
278 if (pmic)
279 mfd_remove_devices(pmic->dev);
280 if (pmic->irq_chip) {
281 pm8xxx_irq_exit(pmic->irq_chip);
282 pmic->irq_chip = NULL;
283 }
284 platform_set_drvdata(pdev, NULL);
285 kfree(pmic);
286
287 return 0;
288}
289
290static struct platform_driver pm8821_driver = {
291 .probe = pm8821_probe,
292 .remove = __devexit_p(pm8821_remove),
293 .driver = {
294 .name = "pm8821-core",
295 .owner = THIS_MODULE,
296 },
297};
298
299static int __init pm8821_init(void)
300{
301 return platform_driver_register(&pm8821_driver);
302}
303postcore_initcall(pm8821_init);
304
305static void __exit pm8821_exit(void)
306{
307 platform_driver_unregister(&pm8821_driver);
308}
309module_exit(pm8821_exit);
310
311MODULE_LICENSE("GPL v2");
312MODULE_DESCRIPTION("PMIC 8821 core driver");
313MODULE_VERSION("1.0");
314MODULE_ALIAS("platform:pm8821-core");