Save sram context after changing MPU, DSP or core clocks
[linux-ginger.git] / drivers / cbus / cbus.c
blobc80cedec68b4ebe25c09087eacb7c2625ac167fb
1 /*
2 * drivers/cbus/cbus.c
4 * Support functions for CBUS serial protocol
6 * Copyright (C) 2004, 2005 Nokia Corporation
8 * Written by Juha Yrjölä <juha.yrjola@nokia.com>,
9 * David Weinehall <david.weinehall@nokia.com>, and
10 * Mikko Ylinen <mikko.k.ylinen@nokia.com>
12 * This file is subject to the terms and conditions of the GNU General
13 * Public License. See the file "COPYING" in the main directory of this
14 * archive for more details.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 #include <linux/device.h>
27 #include <linux/init.h>
28 #include <linux/kernel.h>
29 #include <linux/delay.h>
30 #include <linux/spinlock.h>
31 #include <linux/gpio.h>
33 #include <asm/io.h>
34 #include <asm/mach-types.h>
36 #include <plat/board.h>
38 #include "cbus.h"
40 struct cbus_host *cbus_host = NULL;
42 #ifdef CONFIG_ARCH_OMAP1
43 /* We use our own MPUIO functions to get closer to 1MHz bus speed */
45 static inline void cbus_set_gpio_direction(u32 base, int mpuio, int is_input)
47 u16 w;
49 mpuio &= 0x0f;
50 w = __raw_readw(base + OMAP_MPUIO_IO_CNTL);
51 if (is_input)
52 w |= 1 << mpuio;
53 else
54 w &= ~(1 << mpuio);
55 __raw_writew(w, base + OMAP_MPUIO_IO_CNTL);
59 static inline void cbus_set_gpio_dataout(u32 base, int mpuio, int enable)
61 u16 w;
63 mpuio &= 0x0f;
64 w = __raw_readw(base + OMAP_MPUIO_OUTPUT);
65 if (enable)
66 w |= 1 << mpuio;
67 else
68 w &= ~(1 << mpuio);
69 __raw_writew(w, base + OMAP_MPUIO_OUTPUT);
72 static inline int cbus_get_gpio_datain(u32 base, int mpuio)
74 mpuio &= 0x0f;
76 return (__raw_readw(base + OMAP_MPUIO_INPUT_LATCH) & (1 << mpuio)) != 0;
79 static void cbus_send_bit(struct cbus_host *host, u32 base, int bit,
80 int set_to_input)
82 cbus_set_gpio_dataout(base, host->dat_gpio, bit ? 1 : 0);
83 cbus_set_gpio_dataout(base, host->clk_gpio, 1);
85 /* The data bit is read on the rising edge of CLK */
86 if (set_to_input)
87 cbus_set_gpio_direction(base, host->dat_gpio, 1);
89 cbus_set_gpio_dataout(base, host->clk_gpio, 0);
92 static u8 cbus_receive_bit(struct cbus_host *host, u32 base)
94 u8 ret;
96 cbus_set_gpio_dataout(base, host->clk_gpio, 1);
97 ret = cbus_get_gpio_datain(base, host->dat_gpio);
98 cbus_set_gpio_dataout(base, host->clk_gpio, 0);
100 return ret;
103 #define cbus_output(base, gpio, val) cbus_set_gpio_direction(base, gpio, 0)
105 #else
107 #define cbus_output(base, gpio, val) gpio_direction_output(gpio, val)
108 #define cbus_set_gpio_dataout(base, gpio, enable) gpio_set_value(gpio, enable)
109 #define cbus_get_gpio_datain(base, int, gpio) gpio_get_value(gpio)
111 static void _cbus_send_bit(struct cbus_host *host, int bit, int set_to_input)
113 gpio_set_value(host->dat_gpio, bit ? 1 : 0);
114 gpio_set_value(host->clk_gpio, 1);
116 /* The data bit is read on the rising edge of CLK */
117 if (set_to_input)
118 gpio_direction_input(host->dat_gpio);
120 gpio_set_value(host->clk_gpio, 0);
123 static u8 _cbus_receive_bit(struct cbus_host *host)
125 u8 ret;
127 gpio_set_value(host->clk_gpio, 1);
128 ret = gpio_get_value(host->dat_gpio);
129 gpio_set_value(host->clk_gpio, 0);
131 return ret;
134 #define cbus_send_bit(host, base, bit, set_to_input) _cbus_send_bit(host, bit, set_to_input)
135 #define cbus_receive_bit(host, base) _cbus_receive_bit(host)
137 #endif
139 static int cbus_transfer(struct cbus_host *host, int dev, int reg, int data)
141 int i;
142 int is_read = 0;
143 unsigned long flags;
144 u32 base;
146 #ifdef CONFIG_ARCH_OMAP1
147 base = OMAP1_IO_ADDRESS(OMAP1_MPUIO_BASE);
148 #else
149 base = 0;
150 #endif
152 if (data < 0)
153 is_read = 1;
155 /* We don't want interrupts disturbing our transfer */
156 spin_lock_irqsave(&host->lock, flags);
158 /* Reset state and start of transfer, SEL stays down during transfer */
159 cbus_set_gpio_dataout(base, host->sel_gpio, 0);
161 /* Set the DAT pin to output */
162 cbus_output(base, host->dat_gpio, 1);
164 /* Send the device address */
165 for (i = 3; i > 0; i--)
166 cbus_send_bit(host, base, dev & (1 << (i - 1)), 0);
168 /* Send the rw flag */
169 cbus_send_bit(host, base, is_read, 0);
171 /* Send the register address */
172 for (i = 5; i > 0; i--) {
173 int set_to_input = 0;
175 if (is_read && i == 1)
176 set_to_input = 1;
178 cbus_send_bit(host, base, reg & (1 << (i - 1)), set_to_input);
181 if (!is_read) {
182 for (i = 16; i > 0; i--)
183 cbus_send_bit(host, base, data & (1 << (i - 1)), 0);
184 } else {
185 cbus_set_gpio_dataout(base, host->clk_gpio, 1);
186 data = 0;
188 for (i = 16; i > 0; i--) {
189 u8 bit = cbus_receive_bit(host, base);
191 if (bit)
192 data |= 1 << (i - 1);
196 /* Indicate end of transfer, SEL goes up until next transfer */
197 cbus_set_gpio_dataout(base, host->sel_gpio, 1);
198 cbus_set_gpio_dataout(base, host->clk_gpio, 1);
199 cbus_set_gpio_dataout(base, host->clk_gpio, 0);
201 spin_unlock_irqrestore(&host->lock, flags);
203 return is_read ? data : 0;
207 * Read a given register from the device
209 int cbus_read_reg(struct cbus_host *host, int dev, int reg)
211 return cbus_host ? cbus_transfer(host, dev, reg, -1) : -ENODEV;
215 * Write to a given register of the device
217 int cbus_write_reg(struct cbus_host *host, int dev, int reg, u16 val)
219 return cbus_host ? cbus_transfer(host, dev, reg, (int)val) : -ENODEV;
222 int __init cbus_bus_init(void)
224 struct cbus_host *chost;
225 int ret;
227 chost = kmalloc(sizeof (*chost), GFP_KERNEL);
228 if (chost == NULL)
229 return -ENOMEM;
231 memset(chost, 0, sizeof (*chost));
233 spin_lock_init(&chost->lock);
235 /* REVISIT: Pass these from board-*.c files in platform_data */
236 if (machine_is_nokia770()) {
237 chost->clk_gpio = OMAP_MPUIO(11);
238 chost->dat_gpio = OMAP_MPUIO(10);
239 chost->sel_gpio = OMAP_MPUIO(9);
240 } else if (machine_is_nokia_n800() || machine_is_nokia_n810() ||
241 machine_is_nokia_n810_wimax()) {
242 chost->clk_gpio = 66;
243 chost->dat_gpio = 65;
244 chost->sel_gpio = 64;
245 } else {
246 printk(KERN_ERR "cbus: Unsupported board\n");
247 ret = -ENODEV;
248 goto exit1;
251 #ifdef CONFIG_ARCH_OMAP1
252 if (!OMAP_GPIO_IS_MPUIO(chost->clk_gpio) ||
253 !OMAP_GPIO_IS_MPUIO(chost->dat_gpio) ||
254 !OMAP_GPIO_IS_MPUIO(chost->sel_gpio)) {
255 printk(KERN_ERR "cbus: Only MPUIO pins supported\n");
256 ret = -ENODEV;
257 goto exit1;
259 #endif
261 if ((ret = gpio_request(chost->clk_gpio, "CBUS clk")) < 0)
262 goto exit1;
264 if ((ret = gpio_request(chost->dat_gpio, "CBUS data")) < 0)
265 goto exit2;
267 if ((ret = gpio_request(chost->sel_gpio, "CBUS sel")) < 0)
268 goto exit3;
270 gpio_direction_output(chost->clk_gpio, 0);
271 gpio_direction_input(chost->dat_gpio);
272 gpio_direction_output(chost->sel_gpio, 1);
274 gpio_set_value(chost->clk_gpio, 1);
275 gpio_set_value(chost->clk_gpio, 0);
277 cbus_host = chost;
279 return 0;
280 exit3:
281 gpio_free(chost->dat_gpio);
282 exit2:
283 gpio_free(chost->clk_gpio);
284 exit1:
285 kfree(chost);
286 return ret;
289 subsys_initcall(cbus_bus_init);
291 EXPORT_SYMBOL(cbus_host);
292 EXPORT_SYMBOL(cbus_read_reg);
293 EXPORT_SYMBOL(cbus_write_reg);
295 MODULE_DESCRIPTION("CBUS serial protocol");
296 MODULE_LICENSE("GPL");
297 MODULE_AUTHOR("Juha Yrjölä, David Weinehall, and Mikko Ylinen");