Merge branch '83xx' into for_paulus
[linux-2.6] / arch / arm / mach-pxa / corgi_ssp.c
1 /*
2  *  SSP control code for Sharp Corgi devices
3  *
4  *  Copyright (c) 2004-2005 Richard Purdie
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License version 2 as
8  *  published by the Free Software Foundation.
9  *
10  */
11
12 #include <linux/module.h>
13 #include <linux/init.h>
14 #include <linux/kernel.h>
15 #include <linux/sched.h>
16 #include <linux/slab.h>
17 #include <linux/delay.h>
18 #include <linux/platform_device.h>
19 #include <asm/hardware.h>
20 #include <asm/mach-types.h>
21
22 #include <asm/arch/ssp.h>
23 #include <asm/arch/pxa-regs.h>
24 #include "sharpsl.h"
25
26 static DEFINE_SPINLOCK(corgi_ssp_lock);
27 static struct ssp_dev corgi_ssp_dev;
28 static struct ssp_state corgi_ssp_state;
29 static struct corgissp_machinfo *ssp_machinfo;
30
31 /*
32  * There are three devices connected to the SSP interface:
33  *   1. A touchscreen controller (TI ADS7846 compatible)
34  *   2. An LCD contoller (with some Backlight functionality)
35  *   3. A battery moinitoring IC (Maxim MAX1111)
36  *
37  * Each device uses a different speed/mode of communication.
38  *
39  * The touchscreen is very sensitive and the most frequently used
40  * so the port is left configured for this.
41  *
42  * Devices are selected using Chip Selects on GPIOs.
43  */
44
45 /*
46  *  ADS7846 Routines
47  */
48 unsigned long corgi_ssp_ads7846_putget(ulong data)
49 {
50         unsigned long ret,flag;
51
52         spin_lock_irqsave(&corgi_ssp_lock, flag);
53         if (ssp_machinfo->cs_ads7846 >= 0)
54                 GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
55
56         ssp_write_word(&corgi_ssp_dev,data);
57         ret = ssp_read_word(&corgi_ssp_dev);
58
59         if (ssp_machinfo->cs_ads7846 >= 0)
60                 GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
61         spin_unlock_irqrestore(&corgi_ssp_lock, flag);
62
63         return ret;
64 }
65
66 /*
67  * NOTE: These functions should always be called in interrupt context
68  * and use the _lock and _unlock functions. They are very time sensitive.
69  */
70 void corgi_ssp_ads7846_lock(void)
71 {
72         spin_lock(&corgi_ssp_lock);
73         if (ssp_machinfo->cs_ads7846 >= 0)
74                 GPCR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
75 }
76
77 void corgi_ssp_ads7846_unlock(void)
78 {
79         if (ssp_machinfo->cs_ads7846 >= 0)
80                 GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846);
81         spin_unlock(&corgi_ssp_lock);
82 }
83
84 void corgi_ssp_ads7846_put(ulong data)
85 {
86         ssp_write_word(&corgi_ssp_dev,data);
87 }
88
89 unsigned long corgi_ssp_ads7846_get(void)
90 {
91         return ssp_read_word(&corgi_ssp_dev);
92 }
93
94 EXPORT_SYMBOL(corgi_ssp_ads7846_putget);
95 EXPORT_SYMBOL(corgi_ssp_ads7846_lock);
96 EXPORT_SYMBOL(corgi_ssp_ads7846_unlock);
97 EXPORT_SYMBOL(corgi_ssp_ads7846_put);
98 EXPORT_SYMBOL(corgi_ssp_ads7846_get);
99
100
101 /*
102  *  LCD/Backlight Routines
103  */
104 unsigned long corgi_ssp_dac_put(ulong data)
105 {
106         unsigned long flag, sscr1 = SSCR1_SPH;
107
108         spin_lock_irqsave(&corgi_ssp_lock, flag);
109
110         if (machine_is_spitz() || machine_is_akita() || machine_is_borzoi())
111                 sscr1 = 0;
112
113         ssp_disable(&corgi_ssp_dev);
114         ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), sscr1, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_lcdcon));
115         ssp_enable(&corgi_ssp_dev);
116
117         if (ssp_machinfo->cs_lcdcon >= 0)
118                 GPCR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
119         ssp_write_word(&corgi_ssp_dev,data);
120         /* Read null data back from device to prevent SSP overflow */
121         ssp_read_word(&corgi_ssp_dev);
122         if (ssp_machinfo->cs_lcdcon >= 0)
123                 GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);
124
125         ssp_disable(&corgi_ssp_dev);
126         ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
127         ssp_enable(&corgi_ssp_dev);
128
129         spin_unlock_irqrestore(&corgi_ssp_lock, flag);
130
131         return 0;
132 }
133
134 void corgi_ssp_lcdtg_send(u8 adrs, u8 data)
135 {
136         corgi_ssp_dac_put(((adrs & 0x07) << 5) | (data & 0x1f));
137 }
138
139 void corgi_ssp_blduty_set(int duty)
140 {
141         corgi_ssp_lcdtg_send(0x02,duty);
142 }
143
144 EXPORT_SYMBOL(corgi_ssp_lcdtg_send);
145 EXPORT_SYMBOL(corgi_ssp_blduty_set);
146
147 /*
148  *  Max1111 Routines
149  */
150 int corgi_ssp_max1111_get(ulong data)
151 {
152         unsigned long flag;
153         int voltage,voltage1,voltage2;
154
155         spin_lock_irqsave(&corgi_ssp_lock, flag);
156         if (ssp_machinfo->cs_max1111 >= 0)
157                 GPCR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
158         ssp_disable(&corgi_ssp_dev);
159         ssp_config(&corgi_ssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_max1111));
160         ssp_enable(&corgi_ssp_dev);
161
162         udelay(1);
163
164         /* TB1/RB1 */
165         ssp_write_word(&corgi_ssp_dev,data);
166         ssp_read_word(&corgi_ssp_dev); /* null read */
167
168         /* TB12/RB2 */
169         ssp_write_word(&corgi_ssp_dev,0);
170         voltage1=ssp_read_word(&corgi_ssp_dev);
171
172         /* TB13/RB3*/
173         ssp_write_word(&corgi_ssp_dev,0);
174         voltage2=ssp_read_word(&corgi_ssp_dev);
175
176         ssp_disable(&corgi_ssp_dev);
177         ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
178         ssp_enable(&corgi_ssp_dev);
179         if (ssp_machinfo->cs_max1111 >= 0)
180                 GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111);
181         spin_unlock_irqrestore(&corgi_ssp_lock, flag);
182
183         if (voltage1 & 0xc0 || voltage2 & 0x3f)
184                 voltage = -1;
185         else
186                 voltage = ((voltage1 << 2) & 0xfc) | ((voltage2 >> 6) & 0x03);
187
188         return voltage;
189 }
190
191 EXPORT_SYMBOL(corgi_ssp_max1111_get);
192
193 /*
194  *  Support Routines
195  */
196
197 void __init corgi_ssp_set_machinfo(struct corgissp_machinfo *machinfo)
198 {
199         ssp_machinfo = machinfo;
200 }
201
202 static int __init corgi_ssp_probe(struct platform_device *dev)
203 {
204         int ret;
205
206         /* Chip Select - Disable All */
207         if (ssp_machinfo->cs_lcdcon >= 0)
208                 pxa_gpio_mode(ssp_machinfo->cs_lcdcon  | GPIO_OUT | GPIO_DFLT_HIGH);
209         if (ssp_machinfo->cs_max1111 >= 0)
210                 pxa_gpio_mode(ssp_machinfo->cs_max1111 | GPIO_OUT | GPIO_DFLT_HIGH);
211         if (ssp_machinfo->cs_ads7846 >= 0)
212                 pxa_gpio_mode(ssp_machinfo->cs_ads7846 | GPIO_OUT | GPIO_DFLT_HIGH);
213
214         ret = ssp_init(&corgi_ssp_dev, ssp_machinfo->port, 0);
215
216         if (ret)
217                 printk(KERN_ERR "Unable to register SSP handler!\n");
218         else {
219                 ssp_disable(&corgi_ssp_dev);
220                 ssp_config(&corgi_ssp_dev, (SSCR0_National | (SSCR0_DSS & 0x0b )), 0, 0, SSCR0_SerClkDiv(ssp_machinfo->clk_ads7846));
221                 ssp_enable(&corgi_ssp_dev);
222         }
223
224         return ret;
225 }
226
227 static int corgi_ssp_remove(struct platform_device *dev)
228 {
229         ssp_exit(&corgi_ssp_dev);
230         return 0;
231 }
232
233 static int corgi_ssp_suspend(struct platform_device *dev, pm_message_t state)
234 {
235         ssp_flush(&corgi_ssp_dev);
236         ssp_save_state(&corgi_ssp_dev,&corgi_ssp_state);
237
238         return 0;
239 }
240
241 static int corgi_ssp_resume(struct platform_device *dev)
242 {
243         if (ssp_machinfo->cs_lcdcon >= 0)
244                 GPSR(ssp_machinfo->cs_lcdcon) = GPIO_bit(ssp_machinfo->cs_lcdcon);  /* High - Disable LCD Control/Timing Gen */
245         if (ssp_machinfo->cs_max1111 >= 0)
246                 GPSR(ssp_machinfo->cs_max1111) = GPIO_bit(ssp_machinfo->cs_max1111); /* High - Disable MAX1111*/
247         if (ssp_machinfo->cs_ads7846 >= 0)
248                 GPSR(ssp_machinfo->cs_ads7846) = GPIO_bit(ssp_machinfo->cs_ads7846); /* High - Disable ADS7846*/
249         ssp_restore_state(&corgi_ssp_dev,&corgi_ssp_state);
250         ssp_enable(&corgi_ssp_dev);
251
252         return 0;
253 }
254
255 static struct platform_driver corgissp_driver = {
256         .probe          = corgi_ssp_probe,
257         .remove         = corgi_ssp_remove,
258         .suspend        = corgi_ssp_suspend,
259         .resume         = corgi_ssp_resume,
260         .driver         = {
261                 .name   = "corgi-ssp",
262         },
263 };
264
265 int __init corgi_ssp_init(void)
266 {
267         return platform_driver_register(&corgissp_driver);
268 }
269
270 arch_initcall(corgi_ssp_init);