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