diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2008-10-09 16:33:02 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2008-10-09 16:33:02 -0400 |
commit | 3f30a09a612bac2b531a206c2a58a292dd7ff182 (patch) | |
tree | 62741c2f78aeb3009c66dbcf014ebff2e034e597 /drivers | |
parent | 9e165acf1b9e37af7c0fa39399b43d0bd8600039 (diff) | |
parent | fda50a1c49ad7483eaa29a268d560422c413933f (diff) |
Merge branch 'pxa-all' into devel
Conflicts:
arch/arm/mach-pxa/Kconfig
arch/arm/mach-pxa/corgi.c
arch/arm/mach-pxa/include/mach/hardware.h
arch/arm/mach-pxa/spitz.c
Diffstat (limited to 'drivers')
47 files changed, 3209 insertions, 1330 deletions
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig index d402e8d813ce..3309e862f317 100644 --- a/drivers/hwmon/Kconfig +++ b/drivers/hwmon/Kconfig | |||
@@ -540,6 +540,15 @@ config SENSORS_LM93 | |||
540 | This driver can also be built as a module. If so, the module | 540 | This driver can also be built as a module. If so, the module |
541 | will be called lm93. | 541 | will be called lm93. |
542 | 542 | ||
543 | config SENSORS_MAX1111 | ||
544 | tristate "Maxim MAX1111 Multichannel, Serial 8-bit ADC chip" | ||
545 | depends on SPI_MASTER | ||
546 | help | ||
547 | Say y here to support Maxim's MAX1111 ADC chips. | ||
548 | |||
549 | This driver can also be built as a module. If so, the module | ||
550 | will be called max1111. | ||
551 | |||
543 | config SENSORS_MAX1619 | 552 | config SENSORS_MAX1619 |
544 | tristate "Maxim MAX1619 sensor chip" | 553 | tristate "Maxim MAX1619 sensor chip" |
545 | depends on I2C | 554 | depends on I2C |
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile index 950134ab8426..6babc801b348 100644 --- a/drivers/hwmon/Makefile +++ b/drivers/hwmon/Makefile | |||
@@ -59,6 +59,7 @@ obj-$(CONFIG_SENSORS_LM87) += lm87.o | |||
59 | obj-$(CONFIG_SENSORS_LM90) += lm90.o | 59 | obj-$(CONFIG_SENSORS_LM90) += lm90.o |
60 | obj-$(CONFIG_SENSORS_LM92) += lm92.o | 60 | obj-$(CONFIG_SENSORS_LM92) += lm92.o |
61 | obj-$(CONFIG_SENSORS_LM93) += lm93.o | 61 | obj-$(CONFIG_SENSORS_LM93) += lm93.o |
62 | obj-$(CONFIG_SENSORS_MAX1111) += max1111.o | ||
62 | obj-$(CONFIG_SENSORS_MAX1619) += max1619.o | 63 | obj-$(CONFIG_SENSORS_MAX1619) += max1619.o |
63 | obj-$(CONFIG_SENSORS_MAX6650) += max6650.o | 64 | obj-$(CONFIG_SENSORS_MAX6650) += max6650.o |
64 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o | 65 | obj-$(CONFIG_SENSORS_PC87360) += pc87360.o |
diff --git a/drivers/hwmon/max1111.c b/drivers/hwmon/max1111.c new file mode 100644 index 000000000000..bfaa665ccf32 --- /dev/null +++ b/drivers/hwmon/max1111.c | |||
@@ -0,0 +1,244 @@ | |||
1 | /* | ||
2 | * max1111.c - +2.7V, Low-Power, Multichannel, Serial 8-bit ADCs | ||
3 | * | ||
4 | * Based on arch/arm/mach-pxa/corgi_ssp.c | ||
5 | * | ||
6 | * Copyright (C) 2004-2005 Richard Purdie | ||
7 | * | ||
8 | * Copyright (C) 2008 Marvell International Ltd. | ||
9 | * Eric Miao <eric.miao@marvell.com> | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * publishhed by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/module.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/err.h> | ||
20 | #include <linux/hwmon.h> | ||
21 | #include <linux/hwmon-sysfs.h> | ||
22 | #include <linux/spi/spi.h> | ||
23 | |||
24 | #define MAX1111_TX_BUF_SIZE 1 | ||
25 | #define MAX1111_RX_BUF_SIZE 2 | ||
26 | |||
27 | /* MAX1111 Commands */ | ||
28 | #define MAX1111_CTRL_PD0 (1u << 0) | ||
29 | #define MAX1111_CTRL_PD1 (1u << 1) | ||
30 | #define MAX1111_CTRL_SGL (1u << 2) | ||
31 | #define MAX1111_CTRL_UNI (1u << 3) | ||
32 | #define MAX1111_CTRL_SEL_SH (5) /* NOTE: bit 4 is ignored */ | ||
33 | #define MAX1111_CTRL_STR (1u << 7) | ||
34 | |||
35 | struct max1111_data { | ||
36 | struct spi_device *spi; | ||
37 | struct device *hwmon_dev; | ||
38 | struct spi_message msg; | ||
39 | struct spi_transfer xfer[2]; | ||
40 | uint8_t *tx_buf; | ||
41 | uint8_t *rx_buf; | ||
42 | }; | ||
43 | |||
44 | static int max1111_read(struct device *dev, int channel) | ||
45 | { | ||
46 | struct max1111_data *data = dev_get_drvdata(dev); | ||
47 | uint8_t v1, v2; | ||
48 | int err; | ||
49 | |||
50 | data->tx_buf[0] = (channel << MAX1111_CTRL_SEL_SH) | | ||
51 | MAX1111_CTRL_PD0 | MAX1111_CTRL_PD1 | | ||
52 | MAX1111_CTRL_SGL | MAX1111_CTRL_UNI | MAX1111_CTRL_STR; | ||
53 | |||
54 | err = spi_sync(data->spi, &data->msg); | ||
55 | if (err < 0) { | ||
56 | dev_err(dev, "spi_sync failed with %d\n", err); | ||
57 | return err; | ||
58 | } | ||
59 | |||
60 | v1 = data->rx_buf[0]; | ||
61 | v2 = data->rx_buf[1]; | ||
62 | |||
63 | if ((v1 & 0xc0) || (v2 & 0x3f)) | ||
64 | return -EINVAL; | ||
65 | |||
66 | return (v1 << 2) | (v2 >> 6); | ||
67 | } | ||
68 | |||
69 | #ifdef CONFIG_SHARPSL_PM | ||
70 | static struct max1111_data *the_max1111; | ||
71 | |||
72 | int max1111_read_channel(int channel) | ||
73 | { | ||
74 | return max1111_read(&the_max1111->spi->dev, channel); | ||
75 | } | ||
76 | EXPORT_SYMBOL(max1111_read_channel); | ||
77 | #endif | ||
78 | |||
79 | /* | ||
80 | * NOTE: SPI devices do not have a default 'name' attribute, which is | ||
81 | * likely to be used by hwmon applications to distinguish between | ||
82 | * different devices, explicitly add a name attribute here. | ||
83 | */ | ||
84 | static ssize_t show_name(struct device *dev, | ||
85 | struct device_attribute *attr, char *buf) | ||
86 | { | ||
87 | return sprintf(buf, "max1111\n"); | ||
88 | } | ||
89 | |||
90 | static ssize_t show_adc(struct device *dev, | ||
91 | struct device_attribute *attr, char *buf) | ||
92 | { | ||
93 | int channel = to_sensor_dev_attr(attr)->index; | ||
94 | int ret; | ||
95 | |||
96 | ret = max1111_read(dev, channel); | ||
97 | if (ret < 0) | ||
98 | return ret; | ||
99 | |||
100 | return sprintf(buf, "%d\n", ret); | ||
101 | } | ||
102 | |||
103 | #define MAX1111_ADC_ATTR(_id) \ | ||
104 | SENSOR_DEVICE_ATTR(adc##_id##_in, S_IRUGO, show_adc, NULL, _id) | ||
105 | |||
106 | static DEVICE_ATTR(name, S_IRUGO, show_name, NULL); | ||
107 | static MAX1111_ADC_ATTR(0); | ||
108 | static MAX1111_ADC_ATTR(1); | ||
109 | static MAX1111_ADC_ATTR(2); | ||
110 | static MAX1111_ADC_ATTR(3); | ||
111 | |||
112 | static struct attribute *max1111_attributes[] = { | ||
113 | &dev_attr_name.attr, | ||
114 | &sensor_dev_attr_adc0_in.dev_attr.attr, | ||
115 | &sensor_dev_attr_adc1_in.dev_attr.attr, | ||
116 | &sensor_dev_attr_adc2_in.dev_attr.attr, | ||
117 | &sensor_dev_attr_adc3_in.dev_attr.attr, | ||
118 | NULL, | ||
119 | }; | ||
120 | |||
121 | static const struct attribute_group max1111_attr_group = { | ||
122 | .attrs = max1111_attributes, | ||
123 | }; | ||
124 | |||
125 | static int setup_transfer(struct max1111_data *data) | ||
126 | { | ||
127 | struct spi_message *m; | ||
128 | struct spi_transfer *x; | ||
129 | |||
130 | data->tx_buf = kmalloc(MAX1111_TX_BUF_SIZE, GFP_KERNEL); | ||
131 | if (!data->tx_buf) | ||
132 | return -ENOMEM; | ||
133 | |||
134 | data->rx_buf = kmalloc(MAX1111_RX_BUF_SIZE, GFP_KERNEL); | ||
135 | if (!data->rx_buf) { | ||
136 | kfree(data->tx_buf); | ||
137 | return -ENOMEM; | ||
138 | } | ||
139 | |||
140 | m = &data->msg; | ||
141 | x = &data->xfer[0]; | ||
142 | |||
143 | spi_message_init(m); | ||
144 | |||
145 | x->tx_buf = &data->tx_buf[0]; | ||
146 | x->len = 1; | ||
147 | spi_message_add_tail(x, m); | ||
148 | |||
149 | x++; | ||
150 | x->rx_buf = &data->rx_buf[0]; | ||
151 | x->len = 2; | ||
152 | spi_message_add_tail(x, m); | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | static int __devinit max1111_probe(struct spi_device *spi) | ||
158 | { | ||
159 | struct max1111_data *data; | ||
160 | int err; | ||
161 | |||
162 | spi->bits_per_word = 8; | ||
163 | spi->mode = SPI_MODE_0; | ||
164 | err = spi_setup(spi); | ||
165 | if (err < 0) | ||
166 | return err; | ||
167 | |||
168 | data = kzalloc(sizeof(struct max1111_data), GFP_KERNEL); | ||
169 | if (data == NULL) { | ||
170 | dev_err(&spi->dev, "failed to allocate memory\n"); | ||
171 | return -ENOMEM; | ||
172 | } | ||
173 | |||
174 | err = setup_transfer(data); | ||
175 | if (err) | ||
176 | goto err_free_data; | ||
177 | |||
178 | data->spi = spi; | ||
179 | spi_set_drvdata(spi, data); | ||
180 | |||
181 | err = sysfs_create_group(&spi->dev.kobj, &max1111_attr_group); | ||
182 | if (err) { | ||
183 | dev_err(&spi->dev, "failed to create attribute group\n"); | ||
184 | goto err_free_all; | ||
185 | } | ||
186 | |||
187 | data->hwmon_dev = hwmon_device_register(&spi->dev); | ||
188 | if (IS_ERR(data->hwmon_dev)) { | ||
189 | dev_err(&spi->dev, "failed to create hwmon device\n"); | ||
190 | err = PTR_ERR(data->hwmon_dev); | ||
191 | goto err_remove; | ||
192 | } | ||
193 | |||
194 | #ifdef CONFIG_SHARPSL_PM | ||
195 | the_max1111 = data; | ||
196 | #endif | ||
197 | return 0; | ||
198 | |||
199 | err_remove: | ||
200 | sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group); | ||
201 | err_free_all: | ||
202 | kfree(data->rx_buf); | ||
203 | kfree(data->tx_buf); | ||
204 | err_free_data: | ||
205 | kfree(data); | ||
206 | return err; | ||
207 | } | ||
208 | |||
209 | static int __devexit max1111_remove(struct spi_device *spi) | ||
210 | { | ||
211 | struct max1111_data *data = spi_get_drvdata(spi); | ||
212 | |||
213 | hwmon_device_unregister(data->hwmon_dev); | ||
214 | sysfs_remove_group(&spi->dev.kobj, &max1111_attr_group); | ||
215 | kfree(data->rx_buf); | ||
216 | kfree(data->tx_buf); | ||
217 | kfree(data); | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | static struct spi_driver max1111_driver = { | ||
222 | .driver = { | ||
223 | .name = "max1111", | ||
224 | .owner = THIS_MODULE, | ||
225 | }, | ||
226 | .probe = max1111_probe, | ||
227 | .remove = __devexit_p(max1111_remove), | ||
228 | }; | ||
229 | |||
230 | static int __init max1111_init(void) | ||
231 | { | ||
232 | return spi_register_driver(&max1111_driver); | ||
233 | } | ||
234 | module_init(max1111_init); | ||
235 | |||
236 | static void __exit max1111_exit(void) | ||
237 | { | ||
238 | spi_unregister_driver(&max1111_driver); | ||
239 | } | ||
240 | module_exit(max1111_exit); | ||
241 | |||
242 | MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"); | ||
243 | MODULE_DESCRIPTION("MAX1111 ADC Driver"); | ||
244 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/i2c/busses/i2c-pxa.c b/drivers/i2c/busses/i2c-pxa.c index 44d838410f15..906f9b9d715d 100644 --- a/drivers/i2c/busses/i2c-pxa.c +++ b/drivers/i2c/busses/i2c-pxa.c | |||
@@ -38,7 +38,44 @@ | |||
38 | #include <asm/irq.h> | 38 | #include <asm/irq.h> |
39 | #include <asm/io.h> | 39 | #include <asm/io.h> |
40 | #include <mach/i2c.h> | 40 | #include <mach/i2c.h> |
41 | #include <mach/pxa-regs.h> | 41 | |
42 | /* | ||
43 | * I2C registers and bit definitions | ||
44 | */ | ||
45 | #define IBMR (0x00) | ||
46 | #define IDBR (0x08) | ||
47 | #define ICR (0x10) | ||
48 | #define ISR (0x18) | ||
49 | #define ISAR (0x20) | ||
50 | |||
51 | #define ICR_START (1 << 0) /* start bit */ | ||
52 | #define ICR_STOP (1 << 1) /* stop bit */ | ||
53 | #define ICR_ACKNAK (1 << 2) /* send ACK(0) or NAK(1) */ | ||
54 | #define ICR_TB (1 << 3) /* transfer byte bit */ | ||
55 | #define ICR_MA (1 << 4) /* master abort */ | ||
56 | #define ICR_SCLE (1 << 5) /* master clock enable */ | ||
57 | #define ICR_IUE (1 << 6) /* unit enable */ | ||
58 | #define ICR_GCD (1 << 7) /* general call disable */ | ||
59 | #define ICR_ITEIE (1 << 8) /* enable tx interrupts */ | ||
60 | #define ICR_IRFIE (1 << 9) /* enable rx interrupts */ | ||
61 | #define ICR_BEIE (1 << 10) /* enable bus error ints */ | ||
62 | #define ICR_SSDIE (1 << 11) /* slave STOP detected int enable */ | ||
63 | #define ICR_ALDIE (1 << 12) /* enable arbitration interrupt */ | ||
64 | #define ICR_SADIE (1 << 13) /* slave address detected int enable */ | ||
65 | #define ICR_UR (1 << 14) /* unit reset */ | ||
66 | #define ICR_FM (1 << 15) /* fast mode */ | ||
67 | |||
68 | #define ISR_RWM (1 << 0) /* read/write mode */ | ||
69 | #define ISR_ACKNAK (1 << 1) /* ack/nak status */ | ||
70 | #define ISR_UB (1 << 2) /* unit busy */ | ||
71 | #define ISR_IBB (1 << 3) /* bus busy */ | ||
72 | #define ISR_SSD (1 << 4) /* slave stop detected */ | ||
73 | #define ISR_ALD (1 << 5) /* arbitration loss detected */ | ||
74 | #define ISR_ITE (1 << 6) /* tx buffer empty */ | ||
75 | #define ISR_IRF (1 << 7) /* rx buffer full */ | ||
76 | #define ISR_GCAD (1 << 8) /* general call address detected */ | ||
77 | #define ISR_SAD (1 << 9) /* slave address detected */ | ||
78 | #define ISR_BED (1 << 10) /* bus error no ACK/NAK */ | ||
42 | 79 | ||
43 | struct pxa_i2c { | 80 | struct pxa_i2c { |
44 | spinlock_t lock; | 81 | spinlock_t lock; |
@@ -60,19 +97,21 @@ struct pxa_i2c { | |||
60 | u32 icrlog[32]; | 97 | u32 icrlog[32]; |
61 | 98 | ||
62 | void __iomem *reg_base; | 99 | void __iomem *reg_base; |
100 | unsigned int reg_shift; | ||
63 | 101 | ||
64 | unsigned long iobase; | 102 | unsigned long iobase; |
65 | unsigned long iosize; | 103 | unsigned long iosize; |
66 | 104 | ||
67 | int irq; | 105 | int irq; |
68 | int use_pio; | 106 | unsigned int use_pio :1; |
107 | unsigned int fast_mode :1; | ||
69 | }; | 108 | }; |
70 | 109 | ||
71 | #define _IBMR(i2c) ((i2c)->reg_base + 0) | 110 | #define _IBMR(i2c) ((i2c)->reg_base + (0x0 << (i2c)->reg_shift)) |
72 | #define _IDBR(i2c) ((i2c)->reg_base + 8) | 111 | #define _IDBR(i2c) ((i2c)->reg_base + (0x4 << (i2c)->reg_shift)) |
73 | #define _ICR(i2c) ((i2c)->reg_base + 0x10) | 112 | #define _ICR(i2c) ((i2c)->reg_base + (0x8 << (i2c)->reg_shift)) |
74 | #define _ISR(i2c) ((i2c)->reg_base + 0x18) | 113 | #define _ISR(i2c) ((i2c)->reg_base + (0xc << (i2c)->reg_shift)) |
75 | #define _ISAR(i2c) ((i2c)->reg_base + 0x20) | 114 | #define _ISAR(i2c) ((i2c)->reg_base + (0x10 << (i2c)->reg_shift)) |
76 | 115 | ||
77 | /* | 116 | /* |
78 | * I2C Slave mode address | 117 | * I2C Slave mode address |
@@ -188,14 +227,14 @@ static inline int i2c_pxa_is_slavemode(struct pxa_i2c *i2c) | |||
188 | 227 | ||
189 | static void i2c_pxa_abort(struct pxa_i2c *i2c) | 228 | static void i2c_pxa_abort(struct pxa_i2c *i2c) |
190 | { | 229 | { |
191 | unsigned long timeout = jiffies + HZ/4; | 230 | int i = 250; |
192 | 231 | ||
193 | if (i2c_pxa_is_slavemode(i2c)) { | 232 | if (i2c_pxa_is_slavemode(i2c)) { |
194 | dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__); | 233 | dev_dbg(&i2c->adap.dev, "%s: called in slave mode\n", __func__); |
195 | return; | 234 | return; |
196 | } | 235 | } |
197 | 236 | ||
198 | while (time_before(jiffies, timeout) && (readl(_IBMR(i2c)) & 0x1) == 0) { | 237 | while ((i > 0) && (readl(_IBMR(i2c)) & 0x1) == 0) { |
199 | unsigned long icr = readl(_ICR(i2c)); | 238 | unsigned long icr = readl(_ICR(i2c)); |
200 | 239 | ||
201 | icr &= ~ICR_START; | 240 | icr &= ~ICR_START; |
@@ -205,7 +244,8 @@ static void i2c_pxa_abort(struct pxa_i2c *i2c) | |||
205 | 244 | ||
206 | show_state(i2c); | 245 | show_state(i2c); |
207 | 246 | ||
208 | msleep(1); | 247 | mdelay(1); |
248 | i --; | ||
209 | } | 249 | } |
210 | 250 | ||
211 | writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP), | 251 | writel(readl(_ICR(i2c)) & ~(ICR_MA | ICR_START | ICR_STOP), |
@@ -364,7 +404,7 @@ static void i2c_pxa_reset(struct pxa_i2c *i2c) | |||
364 | writel(i2c->slave_addr, _ISAR(i2c)); | 404 | writel(i2c->slave_addr, _ISAR(i2c)); |
365 | 405 | ||
366 | /* set control register values */ | 406 | /* set control register values */ |
367 | writel(I2C_ICR_INIT, _ICR(i2c)); | 407 | writel(I2C_ICR_INIT | (i2c->fast_mode ? ICR_FM : 0), _ICR(i2c)); |
368 | 408 | ||
369 | #ifdef CONFIG_I2C_PXA_SLAVE | 409 | #ifdef CONFIG_I2C_PXA_SLAVE |
370 | dev_info(&i2c->adap.dev, "Enabling slave mode\n"); | 410 | dev_info(&i2c->adap.dev, "Enabling slave mode\n"); |
@@ -907,12 +947,6 @@ static int i2c_pxa_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num | |||
907 | struct pxa_i2c *i2c = adap->algo_data; | 947 | struct pxa_i2c *i2c = adap->algo_data; |
908 | int ret, i; | 948 | int ret, i; |
909 | 949 | ||
910 | /* If the I2C controller is disabled we need to reset it (probably due | ||
911 | to a suspend/resume destroying state). We do this here as we can then | ||
912 | avoid worrying about resuming the controller before its users. */ | ||
913 | if (!(readl(_ICR(i2c)) & ICR_IUE)) | ||
914 | i2c_pxa_reset(i2c); | ||
915 | |||
916 | for (i = adap->retries; i >= 0; i--) { | 950 | for (i = adap->retries; i >= 0; i--) { |
917 | ret = i2c_pxa_do_xfer(i2c, msgs, num); | 951 | ret = i2c_pxa_do_xfer(i2c, msgs, num); |
918 | if (ret != I2C_RETRY) | 952 | if (ret != I2C_RETRY) |
@@ -993,6 +1027,7 @@ static int i2c_pxa_probe(struct platform_device *dev) | |||
993 | ret = -EIO; | 1027 | ret = -EIO; |
994 | goto eremap; | 1028 | goto eremap; |
995 | } | 1029 | } |
1030 | i2c->reg_shift = (cpu_is_pxa3xx() && (dev->id == 1)) ? 0 : 1; | ||
996 | 1031 | ||
997 | i2c->iobase = res->start; | 1032 | i2c->iobase = res->start; |
998 | i2c->iosize = res_len(res); | 1033 | i2c->iosize = res_len(res); |
@@ -1013,6 +1048,7 @@ static int i2c_pxa_probe(struct platform_device *dev) | |||
1013 | if (plat) { | 1048 | if (plat) { |
1014 | i2c->adap.class = plat->class; | 1049 | i2c->adap.class = plat->class; |
1015 | i2c->use_pio = plat->use_pio; | 1050 | i2c->use_pio = plat->use_pio; |
1051 | i2c->fast_mode = plat->fast_mode; | ||
1016 | } | 1052 | } |
1017 | 1053 | ||
1018 | if (i2c->use_pio) { | 1054 | if (i2c->use_pio) { |
@@ -1082,9 +1118,33 @@ static int __exit i2c_pxa_remove(struct platform_device *dev) | |||
1082 | return 0; | 1118 | return 0; |
1083 | } | 1119 | } |
1084 | 1120 | ||
1121 | #ifdef CONFIG_PM | ||
1122 | static int i2c_pxa_suspend_late(struct platform_device *dev, pm_message_t state) | ||
1123 | { | ||
1124 | struct pxa_i2c *i2c = platform_get_drvdata(dev); | ||
1125 | clk_disable(i2c->clk); | ||
1126 | return 0; | ||
1127 | } | ||
1128 | |||
1129 | static int i2c_pxa_resume_early(struct platform_device *dev) | ||
1130 | { | ||
1131 | struct pxa_i2c *i2c = platform_get_drvdata(dev); | ||
1132 | |||
1133 | clk_enable(i2c->clk); | ||
1134 | i2c_pxa_reset(i2c); | ||
1135 | |||
1136 | return 0; | ||
1137 | } | ||
1138 | #else | ||
1139 | #define i2c_pxa_suspend_late NULL | ||
1140 | #define i2c_pxa_resume_early NULL | ||
1141 | #endif | ||
1142 | |||
1085 | static struct platform_driver i2c_pxa_driver = { | 1143 | static struct platform_driver i2c_pxa_driver = { |
1086 | .probe = i2c_pxa_probe, | 1144 | .probe = i2c_pxa_probe, |
1087 | .remove = __exit_p(i2c_pxa_remove), | 1145 | .remove = __exit_p(i2c_pxa_remove), |
1146 | .suspend_late = i2c_pxa_suspend_late, | ||
1147 | .resume_early = i2c_pxa_resume_early, | ||
1088 | .driver = { | 1148 | .driver = { |
1089 | .name = "pxa2xx-i2c", | 1149 | .name = "pxa2xx-i2c", |
1090 | .owner = THIS_MODULE, | 1150 | .owner = THIS_MODULE, |
diff --git a/drivers/input/keyboard/corgikbd.c b/drivers/input/keyboard/corgikbd.c index 134e67bf6a90..c8ed065ea0cb 100644 --- a/drivers/input/keyboard/corgikbd.c +++ b/drivers/input/keyboard/corgikbd.c | |||
@@ -80,9 +80,9 @@ struct corgikbd { | |||
80 | #define KB_ACTIVATE_DELAY 10 | 80 | #define KB_ACTIVATE_DELAY 10 |
81 | 81 | ||
82 | /* Helper functions for reading the keyboard matrix | 82 | /* Helper functions for reading the keyboard matrix |
83 | * Note: We should really be using pxa_gpio_mode to alter GPDR but it | 83 | * Note: We should really be using the generic gpio functions to alter |
84 | * requires a function call per GPIO bit which is excessive | 84 | * GPDR but it requires a function call per GPIO bit which is |
85 | * when we need to access 12 bits at once multiple times. | 85 | * excessive when we need to access 12 bits at once, multiple times. |
86 | * These functions must be called within local_irq_save()/local_irq_restore() | 86 | * These functions must be called within local_irq_save()/local_irq_restore() |
87 | * or similar. | 87 | * or similar. |
88 | */ | 88 | */ |
diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index de67b8e0a799..c48b76a46a58 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c | |||
@@ -101,9 +101,9 @@ struct spitzkbd { | |||
101 | #define KB_ACTIVATE_DELAY 10 | 101 | #define KB_ACTIVATE_DELAY 10 |
102 | 102 | ||
103 | /* Helper functions for reading the keyboard matrix | 103 | /* Helper functions for reading the keyboard matrix |
104 | * Note: We should really be using pxa_gpio_mode to alter GPDR but it | 104 | * Note: We should really be using the generic gpio functions to alter |
105 | * requires a function call per GPIO bit which is excessive | 105 | * GPDR but it requires a function call per GPIO bit which is |
106 | * when we need to access 11 bits at once, multiple times. | 106 | * excessive when we need to access 11 bits at once, multiple times. |
107 | * These functions must be called within local_irq_save()/local_irq_restore() | 107 | * These functions must be called within local_irq_save()/local_irq_restore() |
108 | * or similar. | 108 | * or similar. |
109 | */ | 109 | */ |
diff --git a/drivers/input/keyboard/tosakbd.c b/drivers/input/keyboard/tosakbd.c index 44cb50af3ce9..677276b12020 100644 --- a/drivers/input/keyboard/tosakbd.c +++ b/drivers/input/keyboard/tosakbd.c | |||
@@ -59,9 +59,9 @@ struct tosakbd { | |||
59 | 59 | ||
60 | 60 | ||
61 | /* Helper functions for reading the keyboard matrix | 61 | /* Helper functions for reading the keyboard matrix |
62 | * Note: We should really be using pxa_gpio_mode to alter GPDR but it | 62 | * Note: We should really be using the generic gpio functions to alter |
63 | * requires a function call per GPIO bit which is excessive | 63 | * GPDR but it requires a function call per GPIO bit which is |
64 | * when we need to access 12 bits at once, multiple times. | 64 | * excessive when we need to access 12 bits at once, multiple times. |
65 | * These functions must be called within local_irq_save()/local_irq_restore() | 65 | * These functions must be called within local_irq_save()/local_irq_restore() |
66 | * or similar. | 66 | * or similar. |
67 | */ | 67 | */ |
diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index 25287e80e236..6e1e8c624f9e 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig | |||
@@ -220,6 +220,7 @@ config TOUCHSCREEN_ATMEL_TSADCC | |||
220 | config TOUCHSCREEN_UCB1400 | 220 | config TOUCHSCREEN_UCB1400 |
221 | tristate "Philips UCB1400 touchscreen" | 221 | tristate "Philips UCB1400 touchscreen" |
222 | select AC97_BUS | 222 | select AC97_BUS |
223 | depends on UCB1400_CORE | ||
223 | help | 224 | help |
224 | This enables support for the Philips UCB1400 touchscreen interface. | 225 | This enables support for the Philips UCB1400 touchscreen interface. |
225 | The UCB1400 is an AC97 audio codec. The touchscreen interface | 226 | The UCB1400 is an AC97 audio codec. The touchscreen interface |
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index ce6f48c695f5..8583c766d565 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/input.h> | 24 | #include <linux/input.h> |
25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/gpio.h> | ||
27 | #include <linux/spi/spi.h> | 28 | #include <linux/spi/spi.h> |
28 | #include <linux/spi/ads7846.h> | 29 | #include <linux/spi/ads7846.h> |
29 | #include <asm/irq.h> | 30 | #include <asm/irq.h> |
@@ -116,6 +117,7 @@ struct ads7846 { | |||
116 | void *filter_data; | 117 | void *filter_data; |
117 | void (*filter_cleanup)(void *data); | 118 | void (*filter_cleanup)(void *data); |
118 | int (*get_pendown_state)(void); | 119 | int (*get_pendown_state)(void); |
120 | int gpio_pendown; | ||
119 | }; | 121 | }; |
120 | 122 | ||
121 | /* leave chip selected when we're done, for quicker re-select? */ | 123 | /* leave chip selected when we're done, for quicker re-select? */ |
@@ -491,6 +493,14 @@ static struct attribute_group ads784x_attr_group = { | |||
491 | 493 | ||
492 | /*--------------------------------------------------------------------------*/ | 494 | /*--------------------------------------------------------------------------*/ |
493 | 495 | ||
496 | static int get_pendown_state(struct ads7846 *ts) | ||
497 | { | ||
498 | if (ts->get_pendown_state) | ||
499 | return ts->get_pendown_state(); | ||
500 | |||
501 | return !gpio_get_value(ts->gpio_pendown); | ||
502 | } | ||
503 | |||
494 | /* | 504 | /* |
495 | * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, | 505 | * PENIRQ only kicks the timer. The timer only reissues the SPI transfer, |
496 | * to retrieve touchscreen status. | 506 | * to retrieve touchscreen status. |
@@ -550,7 +560,7 @@ static void ads7846_rx(void *ads) | |||
550 | */ | 560 | */ |
551 | if (ts->penirq_recheck_delay_usecs) { | 561 | if (ts->penirq_recheck_delay_usecs) { |
552 | udelay(ts->penirq_recheck_delay_usecs); | 562 | udelay(ts->penirq_recheck_delay_usecs); |
553 | if (!ts->get_pendown_state()) | 563 | if (!get_pendown_state(ts)) |
554 | Rt = 0; | 564 | Rt = 0; |
555 | } | 565 | } |
556 | 566 | ||
@@ -677,7 +687,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) | |||
677 | 687 | ||
678 | spin_lock_irq(&ts->lock); | 688 | spin_lock_irq(&ts->lock); |
679 | 689 | ||
680 | if (unlikely(!ts->get_pendown_state() || | 690 | if (unlikely(!get_pendown_state(ts) || |
681 | device_suspended(&ts->spi->dev))) { | 691 | device_suspended(&ts->spi->dev))) { |
682 | if (ts->pendown) { | 692 | if (ts->pendown) { |
683 | struct input_dev *input = ts->input; | 693 | struct input_dev *input = ts->input; |
@@ -716,7 +726,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) | |||
716 | unsigned long flags; | 726 | unsigned long flags; |
717 | 727 | ||
718 | spin_lock_irqsave(&ts->lock, flags); | 728 | spin_lock_irqsave(&ts->lock, flags); |
719 | if (likely(ts->get_pendown_state())) { | 729 | if (likely(get_pendown_state(ts))) { |
720 | if (!ts->irq_disabled) { | 730 | if (!ts->irq_disabled) { |
721 | /* The ARM do_simple_IRQ() dispatcher doesn't act | 731 | /* The ARM do_simple_IRQ() dispatcher doesn't act |
722 | * like the other dispatchers: it will report IRQs | 732 | * like the other dispatchers: it will report IRQs |
@@ -806,6 +816,36 @@ static int ads7846_resume(struct spi_device *spi) | |||
806 | return 0; | 816 | return 0; |
807 | } | 817 | } |
808 | 818 | ||
819 | static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts) | ||
820 | { | ||
821 | struct ads7846_platform_data *pdata = spi->dev.platform_data; | ||
822 | int err; | ||
823 | |||
824 | /* REVISIT when the irq can be triggered active-low, or if for some | ||
825 | * reason the touchscreen isn't hooked up, we don't need to access | ||
826 | * the pendown state. | ||
827 | */ | ||
828 | if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) { | ||
829 | dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n"); | ||
830 | return -EINVAL; | ||
831 | } | ||
832 | |||
833 | if (pdata->get_pendown_state) { | ||
834 | ts->get_pendown_state = pdata->get_pendown_state; | ||
835 | return 0; | ||
836 | } | ||
837 | |||
838 | err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); | ||
839 | if (err) { | ||
840 | dev_err(&spi->dev, "failed to request pendown GPIO%d\n", | ||
841 | pdata->gpio_pendown); | ||
842 | return err; | ||
843 | } | ||
844 | |||
845 | ts->gpio_pendown = pdata->gpio_pendown; | ||
846 | return 0; | ||
847 | } | ||
848 | |||
809 | static int __devinit ads7846_probe(struct spi_device *spi) | 849 | static int __devinit ads7846_probe(struct spi_device *spi) |
810 | { | 850 | { |
811 | struct ads7846 *ts; | 851 | struct ads7846 *ts; |
@@ -833,15 +873,6 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
833 | return -EINVAL; | 873 | return -EINVAL; |
834 | } | 874 | } |
835 | 875 | ||
836 | /* REVISIT when the irq can be triggered active-low, or if for some | ||
837 | * reason the touchscreen isn't hooked up, we don't need to access | ||
838 | * the pendown state. | ||
839 | */ | ||
840 | if (pdata->get_pendown_state == NULL) { | ||
841 | dev_dbg(&spi->dev, "no get_pendown_state function?\n"); | ||
842 | return -EINVAL; | ||
843 | } | ||
844 | |||
845 | /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except | 876 | /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except |
846 | * that even if the hardware can do that, the SPI controller driver | 877 | * that even if the hardware can do that, the SPI controller driver |
847 | * may not. So we stick to very-portable 8 bit words, both RX and TX. | 878 | * may not. So we stick to very-portable 8 bit words, both RX and TX. |
@@ -893,7 +924,10 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
893 | ts->filter_data = ts; | 924 | ts->filter_data = ts; |
894 | } else | 925 | } else |
895 | ts->filter = ads7846_no_filter; | 926 | ts->filter = ads7846_no_filter; |
896 | ts->get_pendown_state = pdata->get_pendown_state; | 927 | |
928 | err = setup_pendown(spi, ts); | ||
929 | if (err) | ||
930 | goto err_cleanup_filter; | ||
897 | 931 | ||
898 | if (pdata->penirq_recheck_delay_usecs) | 932 | if (pdata->penirq_recheck_delay_usecs) |
899 | ts->penirq_recheck_delay_usecs = | 933 | ts->penirq_recheck_delay_usecs = |
@@ -1085,7 +1119,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1085 | spi->dev.driver->name, ts)) { | 1119 | spi->dev.driver->name, ts)) { |
1086 | dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); | 1120 | dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); |
1087 | err = -EBUSY; | 1121 | err = -EBUSY; |
1088 | goto err_cleanup_filter; | 1122 | goto err_free_gpio; |
1089 | } | 1123 | } |
1090 | 1124 | ||
1091 | err = ads784x_hwmon_register(spi, ts); | 1125 | err = ads784x_hwmon_register(spi, ts); |
@@ -1116,6 +1150,9 @@ static int __devinit ads7846_probe(struct spi_device *spi) | |||
1116 | ads784x_hwmon_unregister(spi, ts); | 1150 | ads784x_hwmon_unregister(spi, ts); |
1117 | err_free_irq: | 1151 | err_free_irq: |
1118 | free_irq(spi->irq, ts); | 1152 | free_irq(spi->irq, ts); |
1153 | err_free_gpio: | ||
1154 | if (ts->gpio_pendown != -1) | ||
1155 | gpio_free(ts->gpio_pendown); | ||
1119 | err_cleanup_filter: | 1156 | err_cleanup_filter: |
1120 | if (ts->filter_cleanup) | 1157 | if (ts->filter_cleanup) |
1121 | ts->filter_cleanup(ts->filter_data); | 1158 | ts->filter_cleanup(ts->filter_data); |
@@ -1140,6 +1177,9 @@ static int __devexit ads7846_remove(struct spi_device *spi) | |||
1140 | /* suspend left the IRQ disabled */ | 1177 | /* suspend left the IRQ disabled */ |
1141 | enable_irq(ts->spi->irq); | 1178 | enable_irq(ts->spi->irq); |
1142 | 1179 | ||
1180 | if (ts->gpio_pendown != -1) | ||
1181 | gpio_free(ts->gpio_pendown); | ||
1182 | |||
1143 | if (ts->filter_cleanup) | 1183 | if (ts->filter_cleanup) |
1144 | ts->filter_cleanup(ts->filter_data); | 1184 | ts->filter_cleanup(ts->filter_data); |
1145 | 1185 | ||
diff --git a/drivers/input/touchscreen/ucb1400_ts.c b/drivers/input/touchscreen/ucb1400_ts.c index bce018e45bce..54986627def0 100644 --- a/drivers/input/touchscreen/ucb1400_ts.c +++ b/drivers/input/touchscreen/ucb1400_ts.c | |||
@@ -5,6 +5,10 @@ | |||
5 | * Created: September 25, 2006 | 5 | * Created: September 25, 2006 |
6 | * Copyright: MontaVista Software, Inc. | 6 | * Copyright: MontaVista Software, Inc. |
7 | * | 7 | * |
8 | * Spliting done by: Marek Vasut <marek.vasut@gmail.com> | ||
9 | * If something doesnt work and it worked before spliting, e-mail me, | ||
10 | * dont bother Nicolas please ;-) | ||
11 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | 12 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License version 2 as | 13 | * it under the terms of the GNU General Public License version 2 as |
10 | * published by the Free Software Foundation. | 14 | * published by the Free Software Foundation. |
@@ -25,124 +29,16 @@ | |||
25 | #include <linux/slab.h> | 29 | #include <linux/slab.h> |
26 | #include <linux/kthread.h> | 30 | #include <linux/kthread.h> |
27 | #include <linux/freezer.h> | 31 | #include <linux/freezer.h> |
28 | 32 | #include <linux/ucb1400.h> | |
29 | #include <sound/core.h> | ||
30 | #include <sound/ac97_codec.h> | ||
31 | |||
32 | |||
33 | /* | ||
34 | * Interesting UCB1400 AC-link registers | ||
35 | */ | ||
36 | |||
37 | #define UCB_IE_RIS 0x5e | ||
38 | #define UCB_IE_FAL 0x60 | ||
39 | #define UCB_IE_STATUS 0x62 | ||
40 | #define UCB_IE_CLEAR 0x62 | ||
41 | #define UCB_IE_ADC (1 << 11) | ||
42 | #define UCB_IE_TSPX (1 << 12) | ||
43 | |||
44 | #define UCB_TS_CR 0x64 | ||
45 | #define UCB_TS_CR_TSMX_POW (1 << 0) | ||
46 | #define UCB_TS_CR_TSPX_POW (1 << 1) | ||
47 | #define UCB_TS_CR_TSMY_POW (1 << 2) | ||
48 | #define UCB_TS_CR_TSPY_POW (1 << 3) | ||
49 | #define UCB_TS_CR_TSMX_GND (1 << 4) | ||
50 | #define UCB_TS_CR_TSPX_GND (1 << 5) | ||
51 | #define UCB_TS_CR_TSMY_GND (1 << 6) | ||
52 | #define UCB_TS_CR_TSPY_GND (1 << 7) | ||
53 | #define UCB_TS_CR_MODE_INT (0 << 8) | ||
54 | #define UCB_TS_CR_MODE_PRES (1 << 8) | ||
55 | #define UCB_TS_CR_MODE_POS (2 << 8) | ||
56 | #define UCB_TS_CR_BIAS_ENA (1 << 11) | ||
57 | #define UCB_TS_CR_TSPX_LOW (1 << 12) | ||
58 | #define UCB_TS_CR_TSMX_LOW (1 << 13) | ||
59 | |||
60 | #define UCB_ADC_CR 0x66 | ||
61 | #define UCB_ADC_SYNC_ENA (1 << 0) | ||
62 | #define UCB_ADC_VREFBYP_CON (1 << 1) | ||
63 | #define UCB_ADC_INP_TSPX (0 << 2) | ||
64 | #define UCB_ADC_INP_TSMX (1 << 2) | ||
65 | #define UCB_ADC_INP_TSPY (2 << 2) | ||
66 | #define UCB_ADC_INP_TSMY (3 << 2) | ||
67 | #define UCB_ADC_INP_AD0 (4 << 2) | ||
68 | #define UCB_ADC_INP_AD1 (5 << 2) | ||
69 | #define UCB_ADC_INP_AD2 (6 << 2) | ||
70 | #define UCB_ADC_INP_AD3 (7 << 2) | ||
71 | #define UCB_ADC_EXT_REF (1 << 5) | ||
72 | #define UCB_ADC_START (1 << 7) | ||
73 | #define UCB_ADC_ENA (1 << 15) | ||
74 | |||
75 | #define UCB_ADC_DATA 0x68 | ||
76 | #define UCB_ADC_DAT_VALID (1 << 15) | ||
77 | #define UCB_ADC_DAT_VALUE(x) ((x) & 0x3ff) | ||
78 | |||
79 | #define UCB_ID 0x7e | ||
80 | #define UCB_ID_1400 0x4304 | ||
81 | |||
82 | |||
83 | struct ucb1400 { | ||
84 | struct snd_ac97 *ac97; | ||
85 | struct input_dev *ts_idev; | ||
86 | |||
87 | int irq; | ||
88 | |||
89 | wait_queue_head_t ts_wait; | ||
90 | struct task_struct *ts_task; | ||
91 | |||
92 | unsigned int irq_pending; /* not bit field shared */ | ||
93 | unsigned int ts_restart:1; | ||
94 | unsigned int adcsync:1; | ||
95 | }; | ||
96 | 33 | ||
97 | static int adcsync; | 34 | static int adcsync; |
98 | static int ts_delay = 55; /* us */ | 35 | static int ts_delay = 55; /* us */ |
99 | static int ts_delay_pressure; /* us */ | 36 | static int ts_delay_pressure; /* us */ |
100 | 37 | ||
101 | static inline u16 ucb1400_reg_read(struct ucb1400 *ucb, u16 reg) | ||
102 | { | ||
103 | return ucb->ac97->bus->ops->read(ucb->ac97, reg); | ||
104 | } | ||
105 | |||
106 | static inline void ucb1400_reg_write(struct ucb1400 *ucb, u16 reg, u16 val) | ||
107 | { | ||
108 | ucb->ac97->bus->ops->write(ucb->ac97, reg, val); | ||
109 | } | ||
110 | |||
111 | static inline void ucb1400_adc_enable(struct ucb1400 *ucb) | ||
112 | { | ||
113 | ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); | ||
114 | } | ||
115 | |||
116 | static unsigned int ucb1400_adc_read(struct ucb1400 *ucb, u16 adc_channel) | ||
117 | { | ||
118 | unsigned int val; | ||
119 | |||
120 | if (ucb->adcsync) | ||
121 | adc_channel |= UCB_ADC_SYNC_ENA; | ||
122 | |||
123 | ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | adc_channel); | ||
124 | ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | adc_channel | UCB_ADC_START); | ||
125 | |||
126 | for (;;) { | ||
127 | val = ucb1400_reg_read(ucb, UCB_ADC_DATA); | ||
128 | if (val & UCB_ADC_DAT_VALID) | ||
129 | break; | ||
130 | /* yield to other processes */ | ||
131 | schedule_timeout_uninterruptible(1); | ||
132 | } | ||
133 | |||
134 | return UCB_ADC_DAT_VALUE(val); | ||
135 | } | ||
136 | |||
137 | static inline void ucb1400_adc_disable(struct ucb1400 *ucb) | ||
138 | { | ||
139 | ucb1400_reg_write(ucb, UCB_ADC_CR, 0); | ||
140 | } | ||
141 | |||
142 | /* Switch to interrupt mode. */ | 38 | /* Switch to interrupt mode. */ |
143 | static inline void ucb1400_ts_mode_int(struct ucb1400 *ucb) | 39 | static inline void ucb1400_ts_mode_int(struct snd_ac97 *ac97) |
144 | { | 40 | { |
145 | ucb1400_reg_write(ucb, UCB_TS_CR, | 41 | ucb1400_reg_write(ac97, UCB_TS_CR, |
146 | UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | | 42 | UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | |
147 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | | 43 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | |
148 | UCB_TS_CR_MODE_INT); | 44 | UCB_TS_CR_MODE_INT); |
@@ -152,14 +48,14 @@ static inline void ucb1400_ts_mode_int(struct ucb1400 *ucb) | |||
152 | * Switch to pressure mode, and read pressure. We don't need to wait | 48 | * Switch to pressure mode, and read pressure. We don't need to wait |
153 | * here, since both plates are being driven. | 49 | * here, since both plates are being driven. |
154 | */ | 50 | */ |
155 | static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb) | 51 | static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400_ts *ucb) |
156 | { | 52 | { |
157 | ucb1400_reg_write(ucb, UCB_TS_CR, | 53 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
158 | UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | | 54 | UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW | |
159 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | | 55 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND | |
160 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); | 56 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); |
161 | udelay(ts_delay_pressure); | 57 | udelay(ts_delay_pressure); |
162 | return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY); | 58 | return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync); |
163 | } | 59 | } |
164 | 60 | ||
165 | /* | 61 | /* |
@@ -168,21 +64,21 @@ static inline unsigned int ucb1400_ts_read_pressure(struct ucb1400 *ucb) | |||
168 | * gives a faster response time. Even so, we need to wait about 55us | 64 | * gives a faster response time. Even so, we need to wait about 55us |
169 | * for things to stabilise. | 65 | * for things to stabilise. |
170 | */ | 66 | */ |
171 | static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb) | 67 | static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400_ts *ucb) |
172 | { | 68 | { |
173 | ucb1400_reg_write(ucb, UCB_TS_CR, | 69 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
174 | UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | | 70 | UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | |
175 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); | 71 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); |
176 | ucb1400_reg_write(ucb, UCB_TS_CR, | 72 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
177 | UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | | 73 | UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | |
178 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); | 74 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); |
179 | ucb1400_reg_write(ucb, UCB_TS_CR, | 75 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
180 | UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | | 76 | UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | |
181 | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); | 77 | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); |
182 | 78 | ||
183 | udelay(ts_delay); | 79 | udelay(ts_delay); |
184 | 80 | ||
185 | return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPY); | 81 | return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPY, adcsync); |
186 | } | 82 | } |
187 | 83 | ||
188 | /* | 84 | /* |
@@ -191,63 +87,63 @@ static inline unsigned int ucb1400_ts_read_xpos(struct ucb1400 *ucb) | |||
191 | * gives a faster response time. Even so, we need to wait about 55us | 87 | * gives a faster response time. Even so, we need to wait about 55us |
192 | * for things to stabilise. | 88 | * for things to stabilise. |
193 | */ | 89 | */ |
194 | static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400 *ucb) | 90 | static inline unsigned int ucb1400_ts_read_ypos(struct ucb1400_ts *ucb) |
195 | { | 91 | { |
196 | ucb1400_reg_write(ucb, UCB_TS_CR, | 92 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
197 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | | 93 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | |
198 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); | 94 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); |
199 | ucb1400_reg_write(ucb, UCB_TS_CR, | 95 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
200 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | | 96 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | |
201 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); | 97 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); |
202 | ucb1400_reg_write(ucb, UCB_TS_CR, | 98 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
203 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | | 99 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | |
204 | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); | 100 | UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA); |
205 | 101 | ||
206 | udelay(ts_delay); | 102 | udelay(ts_delay); |
207 | 103 | ||
208 | return ucb1400_adc_read(ucb, UCB_ADC_INP_TSPX); | 104 | return ucb1400_adc_read(ucb->ac97, UCB_ADC_INP_TSPX, adcsync); |
209 | } | 105 | } |
210 | 106 | ||
211 | /* | 107 | /* |
212 | * Switch to X plate resistance mode. Set MX to ground, PX to | 108 | * Switch to X plate resistance mode. Set MX to ground, PX to |
213 | * supply. Measure current. | 109 | * supply. Measure current. |
214 | */ | 110 | */ |
215 | static inline unsigned int ucb1400_ts_read_xres(struct ucb1400 *ucb) | 111 | static inline unsigned int ucb1400_ts_read_xres(struct ucb1400_ts *ucb) |
216 | { | 112 | { |
217 | ucb1400_reg_write(ucb, UCB_TS_CR, | 113 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
218 | UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | | 114 | UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW | |
219 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); | 115 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); |
220 | return ucb1400_adc_read(ucb, 0); | 116 | return ucb1400_adc_read(ucb->ac97, 0, adcsync); |
221 | } | 117 | } |
222 | 118 | ||
223 | /* | 119 | /* |
224 | * Switch to Y plate resistance mode. Set MY to ground, PY to | 120 | * Switch to Y plate resistance mode. Set MY to ground, PY to |
225 | * supply. Measure current. | 121 | * supply. Measure current. |
226 | */ | 122 | */ |
227 | static inline unsigned int ucb1400_ts_read_yres(struct ucb1400 *ucb) | 123 | static inline unsigned int ucb1400_ts_read_yres(struct ucb1400_ts *ucb) |
228 | { | 124 | { |
229 | ucb1400_reg_write(ucb, UCB_TS_CR, | 125 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, |
230 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | | 126 | UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW | |
231 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); | 127 | UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA); |
232 | return ucb1400_adc_read(ucb, 0); | 128 | return ucb1400_adc_read(ucb->ac97, 0, adcsync); |
233 | } | 129 | } |
234 | 130 | ||
235 | static inline int ucb1400_ts_pen_down(struct ucb1400 *ucb) | 131 | static inline int ucb1400_ts_pen_down(struct snd_ac97 *ac97) |
236 | { | 132 | { |
237 | unsigned short val = ucb1400_reg_read(ucb, UCB_TS_CR); | 133 | unsigned short val = ucb1400_reg_read(ac97, UCB_TS_CR); |
238 | return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW)); | 134 | return val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW); |
239 | } | 135 | } |
240 | 136 | ||
241 | static inline void ucb1400_ts_irq_enable(struct ucb1400 *ucb) | 137 | static inline void ucb1400_ts_irq_enable(struct snd_ac97 *ac97) |
242 | { | 138 | { |
243 | ucb1400_reg_write(ucb, UCB_IE_CLEAR, UCB_IE_TSPX); | 139 | ucb1400_reg_write(ac97, UCB_IE_CLEAR, UCB_IE_TSPX); |
244 | ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0); | 140 | ucb1400_reg_write(ac97, UCB_IE_CLEAR, 0); |
245 | ucb1400_reg_write(ucb, UCB_IE_FAL, UCB_IE_TSPX); | 141 | ucb1400_reg_write(ac97, UCB_IE_FAL, UCB_IE_TSPX); |
246 | } | 142 | } |
247 | 143 | ||
248 | static inline void ucb1400_ts_irq_disable(struct ucb1400 *ucb) | 144 | static inline void ucb1400_ts_irq_disable(struct snd_ac97 *ac97) |
249 | { | 145 | { |
250 | ucb1400_reg_write(ucb, UCB_IE_FAL, 0); | 146 | ucb1400_reg_write(ac97, UCB_IE_FAL, 0); |
251 | } | 147 | } |
252 | 148 | ||
253 | static void ucb1400_ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16 y) | 149 | static void ucb1400_ts_evt_add(struct input_dev *idev, u16 pressure, u16 x, u16 y) |
@@ -264,25 +160,24 @@ static void ucb1400_ts_event_release(struct input_dev *idev) | |||
264 | input_sync(idev); | 160 | input_sync(idev); |
265 | } | 161 | } |
266 | 162 | ||
267 | static void ucb1400_handle_pending_irq(struct ucb1400 *ucb) | 163 | static void ucb1400_handle_pending_irq(struct ucb1400_ts *ucb) |
268 | { | 164 | { |
269 | unsigned int isr; | 165 | unsigned int isr; |
270 | 166 | ||
271 | isr = ucb1400_reg_read(ucb, UCB_IE_STATUS); | 167 | isr = ucb1400_reg_read(ucb->ac97, UCB_IE_STATUS); |
272 | ucb1400_reg_write(ucb, UCB_IE_CLEAR, isr); | 168 | ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, isr); |
273 | ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0); | 169 | ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); |
274 | 170 | ||
275 | if (isr & UCB_IE_TSPX) | 171 | if (isr & UCB_IE_TSPX) { |
276 | ucb1400_ts_irq_disable(ucb); | 172 | ucb1400_ts_irq_disable(ucb->ac97); |
277 | else | 173 | enable_irq(ucb->irq); |
174 | } else | ||
278 | printk(KERN_ERR "ucb1400: unexpected IE_STATUS = %#x\n", isr); | 175 | printk(KERN_ERR "ucb1400: unexpected IE_STATUS = %#x\n", isr); |
279 | |||
280 | enable_irq(ucb->irq); | ||
281 | } | 176 | } |
282 | 177 | ||
283 | static int ucb1400_ts_thread(void *_ucb) | 178 | static int ucb1400_ts_thread(void *_ucb) |
284 | { | 179 | { |
285 | struct ucb1400 *ucb = _ucb; | 180 | struct ucb1400_ts *ucb = _ucb; |
286 | struct task_struct *tsk = current; | 181 | struct task_struct *tsk = current; |
287 | int valid = 0; | 182 | int valid = 0; |
288 | struct sched_param param = { .sched_priority = 1 }; | 183 | struct sched_param param = { .sched_priority = 1 }; |
@@ -301,19 +196,19 @@ static int ucb1400_ts_thread(void *_ucb) | |||
301 | ucb1400_handle_pending_irq(ucb); | 196 | ucb1400_handle_pending_irq(ucb); |
302 | } | 197 | } |
303 | 198 | ||
304 | ucb1400_adc_enable(ucb); | 199 | ucb1400_adc_enable(ucb->ac97); |
305 | x = ucb1400_ts_read_xpos(ucb); | 200 | x = ucb1400_ts_read_xpos(ucb); |
306 | y = ucb1400_ts_read_ypos(ucb); | 201 | y = ucb1400_ts_read_ypos(ucb); |
307 | p = ucb1400_ts_read_pressure(ucb); | 202 | p = ucb1400_ts_read_pressure(ucb); |
308 | ucb1400_adc_disable(ucb); | 203 | ucb1400_adc_disable(ucb->ac97); |
309 | 204 | ||
310 | /* Switch back to interrupt mode. */ | 205 | /* Switch back to interrupt mode. */ |
311 | ucb1400_ts_mode_int(ucb); | 206 | ucb1400_ts_mode_int(ucb->ac97); |
312 | 207 | ||
313 | msleep(10); | 208 | msleep(10); |
314 | 209 | ||
315 | if (ucb1400_ts_pen_down(ucb)) { | 210 | if (ucb1400_ts_pen_down(ucb->ac97)) { |
316 | ucb1400_ts_irq_enable(ucb); | 211 | ucb1400_ts_irq_enable(ucb->ac97); |
317 | 212 | ||
318 | /* | 213 | /* |
319 | * If we spat out a valid sample set last time, | 214 | * If we spat out a valid sample set last time, |
@@ -332,8 +227,8 @@ static int ucb1400_ts_thread(void *_ucb) | |||
332 | } | 227 | } |
333 | 228 | ||
334 | wait_event_freezable_timeout(ucb->ts_wait, | 229 | wait_event_freezable_timeout(ucb->ts_wait, |
335 | ucb->irq_pending || ucb->ts_restart || kthread_should_stop(), | 230 | ucb->irq_pending || ucb->ts_restart || |
336 | timeout); | 231 | kthread_should_stop(), timeout); |
337 | } | 232 | } |
338 | 233 | ||
339 | /* Send the "pen off" if we are stopping with the pen still active */ | 234 | /* Send the "pen off" if we are stopping with the pen still active */ |
@@ -356,7 +251,7 @@ static int ucb1400_ts_thread(void *_ucb) | |||
356 | */ | 251 | */ |
357 | static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid) | 252 | static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid) |
358 | { | 253 | { |
359 | struct ucb1400 *ucb = devid; | 254 | struct ucb1400_ts *ucb = devid; |
360 | 255 | ||
361 | if (irqnr == ucb->irq) { | 256 | if (irqnr == ucb->irq) { |
362 | disable_irq(ucb->irq); | 257 | disable_irq(ucb->irq); |
@@ -369,7 +264,7 @@ static irqreturn_t ucb1400_hard_irq(int irqnr, void *devid) | |||
369 | 264 | ||
370 | static int ucb1400_ts_open(struct input_dev *idev) | 265 | static int ucb1400_ts_open(struct input_dev *idev) |
371 | { | 266 | { |
372 | struct ucb1400 *ucb = input_get_drvdata(idev); | 267 | struct ucb1400_ts *ucb = input_get_drvdata(idev); |
373 | int ret = 0; | 268 | int ret = 0; |
374 | 269 | ||
375 | BUG_ON(ucb->ts_task); | 270 | BUG_ON(ucb->ts_task); |
@@ -385,34 +280,14 @@ static int ucb1400_ts_open(struct input_dev *idev) | |||
385 | 280 | ||
386 | static void ucb1400_ts_close(struct input_dev *idev) | 281 | static void ucb1400_ts_close(struct input_dev *idev) |
387 | { | 282 | { |
388 | struct ucb1400 *ucb = input_get_drvdata(idev); | 283 | struct ucb1400_ts *ucb = input_get_drvdata(idev); |
389 | 284 | ||
390 | if (ucb->ts_task) | 285 | if (ucb->ts_task) |
391 | kthread_stop(ucb->ts_task); | 286 | kthread_stop(ucb->ts_task); |
392 | 287 | ||
393 | ucb1400_ts_irq_disable(ucb); | 288 | ucb1400_ts_irq_disable(ucb->ac97); |
394 | ucb1400_reg_write(ucb, UCB_TS_CR, 0); | 289 | ucb1400_reg_write(ucb->ac97, UCB_TS_CR, 0); |
395 | } | ||
396 | |||
397 | #ifdef CONFIG_PM | ||
398 | static int ucb1400_ts_resume(struct device *dev) | ||
399 | { | ||
400 | struct ucb1400 *ucb = dev_get_drvdata(dev); | ||
401 | |||
402 | if (ucb->ts_task) { | ||
403 | /* | ||
404 | * Restart the TS thread to ensure the | ||
405 | * TS interrupt mode is set up again | ||
406 | * after sleep. | ||
407 | */ | ||
408 | ucb->ts_restart = 1; | ||
409 | wake_up(&ucb->ts_wait); | ||
410 | } | ||
411 | return 0; | ||
412 | } | 290 | } |
413 | #else | ||
414 | #define ucb1400_ts_resume NULL | ||
415 | #endif | ||
416 | 291 | ||
417 | #ifndef NO_IRQ | 292 | #ifndef NO_IRQ |
418 | #define NO_IRQ 0 | 293 | #define NO_IRQ 0 |
@@ -422,25 +297,26 @@ static int ucb1400_ts_resume(struct device *dev) | |||
422 | * Try to probe our interrupt, rather than relying on lots of | 297 | * Try to probe our interrupt, rather than relying on lots of |
423 | * hard-coded machine dependencies. | 298 | * hard-coded machine dependencies. |
424 | */ | 299 | */ |
425 | static int ucb1400_detect_irq(struct ucb1400 *ucb) | 300 | static int ucb1400_ts_detect_irq(struct ucb1400_ts *ucb) |
426 | { | 301 | { |
427 | unsigned long mask, timeout; | 302 | unsigned long mask, timeout; |
428 | 303 | ||
429 | mask = probe_irq_on(); | 304 | mask = probe_irq_on(); |
430 | 305 | ||
431 | /* Enable the ADC interrupt. */ | 306 | /* Enable the ADC interrupt. */ |
432 | ucb1400_reg_write(ucb, UCB_IE_RIS, UCB_IE_ADC); | 307 | ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, UCB_IE_ADC); |
433 | ucb1400_reg_write(ucb, UCB_IE_FAL, UCB_IE_ADC); | 308 | ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, UCB_IE_ADC); |
434 | ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0xffff); | 309 | ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff); |
435 | ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0); | 310 | ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); |
436 | 311 | ||
437 | /* Cause an ADC interrupt. */ | 312 | /* Cause an ADC interrupt. */ |
438 | ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA); | 313 | ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA); |
439 | ucb1400_reg_write(ucb, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); | 314 | ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, UCB_ADC_ENA | UCB_ADC_START); |
440 | 315 | ||
441 | /* Wait for the conversion to complete. */ | 316 | /* Wait for the conversion to complete. */ |
442 | timeout = jiffies + HZ/2; | 317 | timeout = jiffies + HZ/2; |
443 | while (!(ucb1400_reg_read(ucb, UCB_ADC_DATA) & UCB_ADC_DAT_VALID)) { | 318 | while (!(ucb1400_reg_read(ucb->ac97, UCB_ADC_DATA) & |
319 | UCB_ADC_DAT_VALID)) { | ||
444 | cpu_relax(); | 320 | cpu_relax(); |
445 | if (time_after(jiffies, timeout)) { | 321 | if (time_after(jiffies, timeout)) { |
446 | printk(KERN_ERR "ucb1400: timed out in IRQ probe\n"); | 322 | printk(KERN_ERR "ucb1400: timed out in IRQ probe\n"); |
@@ -448,13 +324,13 @@ static int ucb1400_detect_irq(struct ucb1400 *ucb) | |||
448 | return -ENODEV; | 324 | return -ENODEV; |
449 | } | 325 | } |
450 | } | 326 | } |
451 | ucb1400_reg_write(ucb, UCB_ADC_CR, 0); | 327 | ucb1400_reg_write(ucb->ac97, UCB_ADC_CR, 0); |
452 | 328 | ||
453 | /* Disable and clear interrupt. */ | 329 | /* Disable and clear interrupt. */ |
454 | ucb1400_reg_write(ucb, UCB_IE_RIS, 0); | 330 | ucb1400_reg_write(ucb->ac97, UCB_IE_RIS, 0); |
455 | ucb1400_reg_write(ucb, UCB_IE_FAL, 0); | 331 | ucb1400_reg_write(ucb->ac97, UCB_IE_FAL, 0); |
456 | ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0xffff); | 332 | ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0xffff); |
457 | ucb1400_reg_write(ucb, UCB_IE_CLEAR, 0); | 333 | ucb1400_reg_write(ucb->ac97, UCB_IE_CLEAR, 0); |
458 | 334 | ||
459 | /* Read triggered interrupt. */ | 335 | /* Read triggered interrupt. */ |
460 | ucb->irq = probe_irq_off(mask); | 336 | ucb->irq = probe_irq_off(mask); |
@@ -464,36 +340,25 @@ static int ucb1400_detect_irq(struct ucb1400 *ucb) | |||
464 | return 0; | 340 | return 0; |
465 | } | 341 | } |
466 | 342 | ||
467 | static int ucb1400_ts_probe(struct device *dev) | 343 | static int ucb1400_ts_probe(struct platform_device *dev) |
468 | { | 344 | { |
469 | struct ucb1400 *ucb; | 345 | int error, x_res, y_res; |
470 | struct input_dev *idev; | 346 | struct ucb1400_ts *ucb = dev->dev.platform_data; |
471 | int error, id, x_res, y_res; | ||
472 | 347 | ||
473 | ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL); | 348 | ucb->ts_idev = input_allocate_device(); |
474 | idev = input_allocate_device(); | 349 | if (!ucb->ts_idev) { |
475 | if (!ucb || !idev) { | ||
476 | error = -ENOMEM; | 350 | error = -ENOMEM; |
477 | goto err_free_devs; | 351 | goto err; |
478 | } | 352 | } |
479 | 353 | ||
480 | ucb->ts_idev = idev; | 354 | error = ucb1400_ts_detect_irq(ucb); |
481 | ucb->adcsync = adcsync; | ||
482 | ucb->ac97 = to_ac97_t(dev); | ||
483 | init_waitqueue_head(&ucb->ts_wait); | ||
484 | |||
485 | id = ucb1400_reg_read(ucb, UCB_ID); | ||
486 | if (id != UCB_ID_1400) { | ||
487 | error = -ENODEV; | ||
488 | goto err_free_devs; | ||
489 | } | ||
490 | |||
491 | error = ucb1400_detect_irq(ucb); | ||
492 | if (error) { | 355 | if (error) { |
493 | printk(KERN_ERR "UCB1400: IRQ probe failed\n"); | 356 | printk(KERN_ERR "UCB1400: IRQ probe failed\n"); |
494 | goto err_free_devs; | 357 | goto err_free_devs; |
495 | } | 358 | } |
496 | 359 | ||
360 | init_waitqueue_head(&ucb->ts_wait); | ||
361 | |||
497 | error = request_irq(ucb->irq, ucb1400_hard_irq, IRQF_TRIGGER_RISING, | 362 | error = request_irq(ucb->irq, ucb1400_hard_irq, IRQF_TRIGGER_RISING, |
498 | "UCB1400", ucb); | 363 | "UCB1400", ucb); |
499 | if (error) { | 364 | if (error) { |
@@ -503,80 +368,101 @@ static int ucb1400_ts_probe(struct device *dev) | |||
503 | } | 368 | } |
504 | printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq); | 369 | printk(KERN_DEBUG "UCB1400: found IRQ %d\n", ucb->irq); |
505 | 370 | ||
506 | input_set_drvdata(idev, ucb); | 371 | input_set_drvdata(ucb->ts_idev, ucb); |
507 | 372 | ||
508 | idev->dev.parent = dev; | 373 | ucb->ts_idev->dev.parent = &dev->dev; |
509 | idev->name = "UCB1400 touchscreen interface"; | 374 | ucb->ts_idev->name = "UCB1400 touchscreen interface"; |
510 | idev->id.vendor = ucb1400_reg_read(ucb, AC97_VENDOR_ID1); | 375 | ucb->ts_idev->id.vendor = ucb1400_reg_read(ucb->ac97, |
511 | idev->id.product = id; | 376 | AC97_VENDOR_ID1); |
512 | idev->open = ucb1400_ts_open; | 377 | ucb->ts_idev->id.product = ucb->id; |
513 | idev->close = ucb1400_ts_close; | 378 | ucb->ts_idev->open = ucb1400_ts_open; |
514 | idev->evbit[0] = BIT_MASK(EV_ABS); | 379 | ucb->ts_idev->close = ucb1400_ts_close; |
380 | ucb->ts_idev->evbit[0] = BIT_MASK(EV_ABS); | ||
515 | 381 | ||
516 | ucb1400_adc_enable(ucb); | 382 | ucb1400_adc_enable(ucb->ac97); |
517 | x_res = ucb1400_ts_read_xres(ucb); | 383 | x_res = ucb1400_ts_read_xres(ucb); |
518 | y_res = ucb1400_ts_read_yres(ucb); | 384 | y_res = ucb1400_ts_read_yres(ucb); |
519 | ucb1400_adc_disable(ucb); | 385 | ucb1400_adc_disable(ucb->ac97); |
520 | printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res); | 386 | printk(KERN_DEBUG "UCB1400: x/y = %d/%d\n", x_res, y_res); |
521 | 387 | ||
522 | input_set_abs_params(idev, ABS_X, 0, x_res, 0, 0); | 388 | input_set_abs_params(ucb->ts_idev, ABS_X, 0, x_res, 0, 0); |
523 | input_set_abs_params(idev, ABS_Y, 0, y_res, 0, 0); | 389 | input_set_abs_params(ucb->ts_idev, ABS_Y, 0, y_res, 0, 0); |
524 | input_set_abs_params(idev, ABS_PRESSURE, 0, 0, 0, 0); | 390 | input_set_abs_params(ucb->ts_idev, ABS_PRESSURE, 0, 0, 0, 0); |
525 | 391 | ||
526 | error = input_register_device(idev); | 392 | error = input_register_device(ucb->ts_idev); |
527 | if (error) | 393 | if (error) |
528 | goto err_free_irq; | 394 | goto err_free_irq; |
529 | 395 | ||
530 | dev_set_drvdata(dev, ucb); | ||
531 | return 0; | 396 | return 0; |
532 | 397 | ||
533 | err_free_irq: | 398 | err_free_irq: |
534 | free_irq(ucb->irq, ucb); | 399 | free_irq(ucb->irq, ucb); |
535 | err_free_devs: | 400 | err_free_devs: |
536 | input_free_device(idev); | 401 | input_free_device(ucb->ts_idev); |
537 | kfree(ucb); | 402 | err: |
538 | return error; | 403 | return error; |
404 | |||
539 | } | 405 | } |
540 | 406 | ||
541 | static int ucb1400_ts_remove(struct device *dev) | 407 | static int ucb1400_ts_remove(struct platform_device *dev) |
542 | { | 408 | { |
543 | struct ucb1400 *ucb = dev_get_drvdata(dev); | 409 | struct ucb1400_ts *ucb = dev->dev.platform_data; |
544 | 410 | ||
545 | free_irq(ucb->irq, ucb); | 411 | free_irq(ucb->irq, ucb); |
546 | input_unregister_device(ucb->ts_idev); | 412 | input_unregister_device(ucb->ts_idev); |
547 | dev_set_drvdata(dev, NULL); | ||
548 | kfree(ucb); | ||
549 | return 0; | 413 | return 0; |
550 | } | 414 | } |
551 | 415 | ||
552 | static struct device_driver ucb1400_ts_driver = { | 416 | #ifdef CONFIG_PM |
553 | .name = "ucb1400_ts", | 417 | static int ucb1400_ts_resume(struct platform_device *dev) |
554 | .owner = THIS_MODULE, | 418 | { |
555 | .bus = &ac97_bus_type, | 419 | struct ucb1400_ts *ucb = platform_get_drvdata(dev); |
556 | .probe = ucb1400_ts_probe, | 420 | |
557 | .remove = ucb1400_ts_remove, | 421 | if (ucb->ts_task) { |
558 | .resume = ucb1400_ts_resume, | 422 | /* |
423 | * Restart the TS thread to ensure the | ||
424 | * TS interrupt mode is set up again | ||
425 | * after sleep. | ||
426 | */ | ||
427 | ucb->ts_restart = 1; | ||
428 | wake_up(&ucb->ts_wait); | ||
429 | } | ||
430 | return 0; | ||
431 | } | ||
432 | #else | ||
433 | #define ucb1400_ts_resume NULL | ||
434 | #endif | ||
435 | |||
436 | static struct platform_driver ucb1400_ts_driver = { | ||
437 | .probe = ucb1400_ts_probe, | ||
438 | .remove = ucb1400_ts_remove, | ||
439 | .resume = ucb1400_ts_resume, | ||
440 | .driver = { | ||
441 | .name = "ucb1400_ts", | ||
442 | }, | ||
559 | }; | 443 | }; |
560 | 444 | ||
561 | static int __init ucb1400_ts_init(void) | 445 | static int __init ucb1400_ts_init(void) |
562 | { | 446 | { |
563 | return driver_register(&ucb1400_ts_driver); | 447 | return platform_driver_register(&ucb1400_ts_driver); |
564 | } | 448 | } |
565 | 449 | ||
566 | static void __exit ucb1400_ts_exit(void) | 450 | static void __exit ucb1400_ts_exit(void) |
567 | { | 451 | { |
568 | driver_unregister(&ucb1400_ts_driver); | 452 | platform_driver_unregister(&ucb1400_ts_driver); |
569 | } | 453 | } |
570 | 454 | ||
571 | module_param(adcsync, bool, 0444); | 455 | module_param(adcsync, bool, 0444); |
572 | MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin."); | 456 | MODULE_PARM_DESC(adcsync, "Synchronize touch readings with ADCSYNC pin."); |
573 | 457 | ||
574 | module_param(ts_delay, int, 0444); | 458 | module_param(ts_delay, int, 0444); |
575 | MODULE_PARM_DESC(ts_delay, "Delay between panel setup and position read. Default = 55us."); | 459 | MODULE_PARM_DESC(ts_delay, "Delay between panel setup and" |
460 | " position read. Default = 55us."); | ||
576 | 461 | ||
577 | module_param(ts_delay_pressure, int, 0444); | 462 | module_param(ts_delay_pressure, int, 0444); |
578 | MODULE_PARM_DESC(ts_delay_pressure, | 463 | MODULE_PARM_DESC(ts_delay_pressure, |
579 | "delay between panel setup and pressure read. Default = 0us."); | 464 | "delay between panel setup and pressure read." |
465 | " Default = 0us."); | ||
580 | 466 | ||
581 | module_init(ucb1400_ts_init); | 467 | module_init(ucb1400_ts_init); |
582 | module_exit(ucb1400_ts_exit); | 468 | module_exit(ucb1400_ts_exit); |
diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig index 9556262dda5a..5b14262af017 100644 --- a/drivers/leds/Kconfig +++ b/drivers/leds/Kconfig | |||
@@ -24,13 +24,6 @@ config LEDS_ATMEL_PWM | |||
24 | This option enables support for LEDs driven using outputs | 24 | This option enables support for LEDs driven using outputs |
25 | of the dedicated PWM controller found on newer Atmel SOCs. | 25 | of the dedicated PWM controller found on newer Atmel SOCs. |
26 | 26 | ||
27 | config LEDS_CORGI | ||
28 | tristate "LED Support for the Sharp SL-C7x0 series" | ||
29 | depends on LEDS_CLASS && PXA_SHARP_C7xx | ||
30 | help | ||
31 | This option enables support for the LEDs on Sharp Zaurus | ||
32 | SL-C7x0 series (C700, C750, C760, C860). | ||
33 | |||
34 | config LEDS_LOCOMO | 27 | config LEDS_LOCOMO |
35 | tristate "LED Support for Locomo device" | 28 | tristate "LED Support for Locomo device" |
36 | depends on LEDS_CLASS && SHARP_LOCOMO | 29 | depends on LEDS_CLASS && SHARP_LOCOMO |
@@ -38,13 +31,6 @@ config LEDS_LOCOMO | |||
38 | This option enables support for the LEDs on Sharp Locomo. | 31 | This option enables support for the LEDs on Sharp Locomo. |
39 | Zaurus models SL-5500 and SL-5600. | 32 | Zaurus models SL-5500 and SL-5600. |
40 | 33 | ||
41 | config LEDS_SPITZ | ||
42 | tristate "LED Support for the Sharp SL-Cxx00 series" | ||
43 | depends on LEDS_CLASS && PXA_SHARP_Cxx00 | ||
44 | help | ||
45 | This option enables support for the LEDs on Sharp Zaurus | ||
46 | SL-Cxx00 series (C1000, C3000, C3100). | ||
47 | |||
48 | config LEDS_S3C24XX | 34 | config LEDS_S3C24XX |
49 | tristate "LED Support for Samsung S3C24XX GPIO LEDs" | 35 | tristate "LED Support for Samsung S3C24XX GPIO LEDs" |
50 | depends on LEDS_CLASS && ARCH_S3C2410 | 36 | depends on LEDS_CLASS && ARCH_S3C2410 |
diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile index ff7982b44565..3a8e6a04363c 100644 --- a/drivers/leds/Makefile +++ b/drivers/leds/Makefile | |||
@@ -6,9 +6,7 @@ obj-$(CONFIG_LEDS_TRIGGERS) += led-triggers.o | |||
6 | 6 | ||
7 | # LED Platform Drivers | 7 | # LED Platform Drivers |
8 | obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o | 8 | obj-$(CONFIG_LEDS_ATMEL_PWM) += leds-atmel-pwm.o |
9 | obj-$(CONFIG_LEDS_CORGI) += leds-corgi.o | ||
10 | obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o | 9 | obj-$(CONFIG_LEDS_LOCOMO) += leds-locomo.o |
11 | obj-$(CONFIG_LEDS_SPITZ) += leds-spitz.o | ||
12 | obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o | 10 | obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c24xx.o |
13 | obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o | 11 | obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o |
14 | obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o | 12 | obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o |
diff --git a/drivers/leds/leds-corgi.c b/drivers/leds/leds-corgi.c deleted file mode 100644 index bc2dcd89f635..000000000000 --- a/drivers/leds/leds-corgi.c +++ /dev/null | |||
@@ -1,124 +0,0 @@ | |||
1 | /* | ||
2 | * LED Triggers Core | ||
3 | * | ||
4 | * Copyright 2005-2006 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <rpurdie@openedhand.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/leds.h> | ||
18 | #include <mach/corgi.h> | ||
19 | #include <mach/hardware.h> | ||
20 | #include <mach/pxa-regs.h> | ||
21 | #include <asm/hardware/scoop.h> | ||
22 | |||
23 | static void corgiled_amber_set(struct led_classdev *led_cdev, | ||
24 | enum led_brightness value) | ||
25 | { | ||
26 | if (value) | ||
27 | GPSR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); | ||
28 | else | ||
29 | GPCR0 = GPIO_bit(CORGI_GPIO_LED_ORANGE); | ||
30 | } | ||
31 | |||
32 | static void corgiled_green_set(struct led_classdev *led_cdev, | ||
33 | enum led_brightness value) | ||
34 | { | ||
35 | if (value) | ||
36 | set_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); | ||
37 | else | ||
38 | reset_scoop_gpio(&corgiscoop_device.dev, CORGI_SCP_LED_GREEN); | ||
39 | } | ||
40 | |||
41 | static struct led_classdev corgi_amber_led = { | ||
42 | .name = "corgi:amber:charge", | ||
43 | .default_trigger = "sharpsl-charge", | ||
44 | .brightness_set = corgiled_amber_set, | ||
45 | }; | ||
46 | |||
47 | static struct led_classdev corgi_green_led = { | ||
48 | .name = "corgi:green:mail", | ||
49 | .default_trigger = "nand-disk", | ||
50 | .brightness_set = corgiled_green_set, | ||
51 | }; | ||
52 | |||
53 | #ifdef CONFIG_PM | ||
54 | static int corgiled_suspend(struct platform_device *dev, pm_message_t state) | ||
55 | { | ||
56 | #ifdef CONFIG_LEDS_TRIGGERS | ||
57 | if (corgi_amber_led.trigger && | ||
58 | strcmp(corgi_amber_led.trigger->name, "sharpsl-charge")) | ||
59 | #endif | ||
60 | led_classdev_suspend(&corgi_amber_led); | ||
61 | led_classdev_suspend(&corgi_green_led); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int corgiled_resume(struct platform_device *dev) | ||
66 | { | ||
67 | led_classdev_resume(&corgi_amber_led); | ||
68 | led_classdev_resume(&corgi_green_led); | ||
69 | return 0; | ||
70 | } | ||
71 | #endif | ||
72 | |||
73 | static int corgiled_probe(struct platform_device *pdev) | ||
74 | { | ||
75 | int ret; | ||
76 | |||
77 | ret = led_classdev_register(&pdev->dev, &corgi_amber_led); | ||
78 | if (ret < 0) | ||
79 | return ret; | ||
80 | |||
81 | ret = led_classdev_register(&pdev->dev, &corgi_green_led); | ||
82 | if (ret < 0) | ||
83 | led_classdev_unregister(&corgi_amber_led); | ||
84 | |||
85 | return ret; | ||
86 | } | ||
87 | |||
88 | static int corgiled_remove(struct platform_device *pdev) | ||
89 | { | ||
90 | led_classdev_unregister(&corgi_amber_led); | ||
91 | led_classdev_unregister(&corgi_green_led); | ||
92 | return 0; | ||
93 | } | ||
94 | |||
95 | static struct platform_driver corgiled_driver = { | ||
96 | .probe = corgiled_probe, | ||
97 | .remove = corgiled_remove, | ||
98 | #ifdef CONFIG_PM | ||
99 | .suspend = corgiled_suspend, | ||
100 | .resume = corgiled_resume, | ||
101 | #endif | ||
102 | .driver = { | ||
103 | .name = "corgi-led", | ||
104 | .owner = THIS_MODULE, | ||
105 | }, | ||
106 | }; | ||
107 | |||
108 | static int __init corgiled_init(void) | ||
109 | { | ||
110 | return platform_driver_register(&corgiled_driver); | ||
111 | } | ||
112 | |||
113 | static void __exit corgiled_exit(void) | ||
114 | { | ||
115 | platform_driver_unregister(&corgiled_driver); | ||
116 | } | ||
117 | |||
118 | module_init(corgiled_init); | ||
119 | module_exit(corgiled_exit); | ||
120 | |||
121 | MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); | ||
122 | MODULE_DESCRIPTION("Corgi LED driver"); | ||
123 | MODULE_LICENSE("GPL"); | ||
124 | MODULE_ALIAS("platform:corgi-led"); | ||
diff --git a/drivers/leds/leds-spitz.c b/drivers/leds/leds-spitz.c deleted file mode 100644 index 178831c64bfb..000000000000 --- a/drivers/leds/leds-spitz.c +++ /dev/null | |||
@@ -1,131 +0,0 @@ | |||
1 | /* | ||
2 | * LED Triggers Core | ||
3 | * | ||
4 | * Copyright 2005-2006 Openedhand Ltd. | ||
5 | * | ||
6 | * Author: Richard Purdie <rpurdie@openedhand.com> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License version 2 as | ||
10 | * published by the Free Software Foundation. | ||
11 | * | ||
12 | */ | ||
13 | |||
14 | #include <linux/kernel.h> | ||
15 | #include <linux/init.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/leds.h> | ||
18 | #include <asm/hardware/scoop.h> | ||
19 | #include <asm/mach-types.h> | ||
20 | #include <mach/hardware.h> | ||
21 | #include <mach/pxa-regs.h> | ||
22 | #include <mach/spitz.h> | ||
23 | |||
24 | static void spitzled_amber_set(struct led_classdev *led_cdev, | ||
25 | enum led_brightness value) | ||
26 | { | ||
27 | if (value) | ||
28 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); | ||
29 | else | ||
30 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_ORANGE); | ||
31 | } | ||
32 | |||
33 | static void spitzled_green_set(struct led_classdev *led_cdev, | ||
34 | enum led_brightness value) | ||
35 | { | ||
36 | if (value) | ||
37 | set_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN); | ||
38 | else | ||
39 | reset_scoop_gpio(&spitzscoop_device.dev, SPITZ_SCP_LED_GREEN); | ||
40 | } | ||
41 | |||
42 | static struct led_classdev spitz_amber_led = { | ||
43 | .name = "spitz:amber:charge", | ||
44 | .default_trigger = "sharpsl-charge", | ||
45 | .brightness_set = spitzled_amber_set, | ||
46 | }; | ||
47 | |||
48 | static struct led_classdev spitz_green_led = { | ||
49 | .name = "spitz:green:hddactivity", | ||
50 | .default_trigger = "ide-disk", | ||
51 | .brightness_set = spitzled_green_set, | ||
52 | }; | ||
53 | |||
54 | #ifdef CONFIG_PM | ||
55 | static int spitzled_suspend(struct platform_device *dev, pm_message_t state) | ||
56 | { | ||
57 | #ifdef CONFIG_LEDS_TRIGGERS | ||
58 | if (spitz_amber_led.trigger && | ||
59 | strcmp(spitz_amber_led.trigger->name, "sharpsl-charge")) | ||
60 | #endif | ||
61 | led_classdev_suspend(&spitz_amber_led); | ||
62 | led_classdev_suspend(&spitz_green_led); | ||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | static int spitzled_resume(struct platform_device *dev) | ||
67 | { | ||
68 | led_classdev_resume(&spitz_amber_led); | ||
69 | led_classdev_resume(&spitz_green_led); | ||
70 | return 0; | ||
71 | } | ||
72 | #endif | ||
73 | |||
74 | static int spitzled_probe(struct platform_device *pdev) | ||
75 | { | ||
76 | int ret; | ||
77 | |||
78 | if (machine_is_akita()) { | ||
79 | spitz_green_led.name = "spitz:green:mail"; | ||
80 | spitz_green_led.default_trigger = "nand-disk"; | ||
81 | } | ||
82 | |||
83 | ret = led_classdev_register(&pdev->dev, &spitz_amber_led); | ||
84 | if (ret < 0) | ||
85 | return ret; | ||
86 | |||
87 | ret = led_classdev_register(&pdev->dev, &spitz_green_led); | ||
88 | if (ret < 0) | ||
89 | led_classdev_unregister(&spitz_amber_led); | ||
90 | |||
91 | return ret; | ||
92 | } | ||
93 | |||
94 | static int spitzled_remove(struct platform_device *pdev) | ||
95 | { | ||
96 | led_classdev_unregister(&spitz_amber_led); | ||
97 | led_classdev_unregister(&spitz_green_led); | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | static struct platform_driver spitzled_driver = { | ||
103 | .probe = spitzled_probe, | ||
104 | .remove = spitzled_remove, | ||
105 | #ifdef CONFIG_PM | ||
106 | .suspend = spitzled_suspend, | ||
107 | .resume = spitzled_resume, | ||
108 | #endif | ||
109 | .driver = { | ||
110 | .name = "spitz-led", | ||
111 | .owner = THIS_MODULE, | ||
112 | }, | ||
113 | }; | ||
114 | |||
115 | static int __init spitzled_init(void) | ||
116 | { | ||
117 | return platform_driver_register(&spitzled_driver); | ||
118 | } | ||
119 | |||
120 | static void __exit spitzled_exit(void) | ||
121 | { | ||
122 | platform_driver_unregister(&spitzled_driver); | ||
123 | } | ||
124 | |||
125 | module_init(spitzled_init); | ||
126 | module_exit(spitzled_exit); | ||
127 | |||
128 | MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>"); | ||
129 | MODULE_DESCRIPTION("Spitz LED driver"); | ||
130 | MODULE_LICENSE("GPL"); | ||
131 | MODULE_ALIAS("platform:spitz-led"); | ||
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c index 388cf94055d3..cf96b2cc4f1c 100644 --- a/drivers/media/video/pxa_camera.c +++ b/drivers/media/video/pxa_camera.c | |||
@@ -1025,9 +1025,9 @@ static int pxa_camera_resume(struct soc_camera_device *icd) | |||
1025 | struct pxa_camera_dev *pcdev = ici->priv; | 1025 | struct pxa_camera_dev *pcdev = ici->priv; |
1026 | int i = 0, ret = 0; | 1026 | int i = 0, ret = 0; |
1027 | 1027 | ||
1028 | DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD; | 1028 | DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; |
1029 | DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD; | 1029 | DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; |
1030 | DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD; | 1030 | DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD; |
1031 | 1031 | ||
1032 | CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB; | 1032 | CICR0 = pcdev->save_cicr[i++] & ~CICR0_ENB; |
1033 | CICR1 = pcdev->save_cicr[i++]; | 1033 | CICR1 = pcdev->save_cicr[i++]; |
@@ -1171,9 +1171,9 @@ static int pxa_camera_probe(struct platform_device *pdev) | |||
1171 | } | 1171 | } |
1172 | dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); | 1172 | dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]); |
1173 | 1173 | ||
1174 | DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD; | 1174 | DRCMR(68) = pcdev->dma_chans[0] | DRCMR_MAPVLD; |
1175 | DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD; | 1175 | DRCMR(69) = pcdev->dma_chans[1] | DRCMR_MAPVLD; |
1176 | DRCMR70 = pcdev->dma_chans[2] | DRCMR_MAPVLD; | 1176 | DRCMR(70) = pcdev->dma_chans[2] | DRCMR_MAPVLD; |
1177 | 1177 | ||
1178 | /* request irq */ | 1178 | /* request irq */ |
1179 | err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME, | 1179 | err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME, |
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig index 10c44d3fe01a..5dba1651f9cc 100644 --- a/drivers/mfd/Kconfig +++ b/drivers/mfd/Kconfig | |||
@@ -50,6 +50,15 @@ config HTC_PASIC3 | |||
50 | HTC Magician devices, respectively. Actual functionality is | 50 | HTC Magician devices, respectively. Actual functionality is |
51 | handled by the leds-pasic3 and ds1wm drivers. | 51 | handled by the leds-pasic3 and ds1wm drivers. |
52 | 52 | ||
53 | config UCB1400_CORE | ||
54 | tristate "Philips UCB1400 Core driver" | ||
55 | help | ||
56 | This enables support for the Philips UCB1400 core functions. | ||
57 | The UCB1400 is an AC97 audio codec. | ||
58 | |||
59 | To compile this driver as a module, choose M here: the | ||
60 | module will be called ucb1400_core. | ||
61 | |||
53 | config MFD_TMIO | 62 | config MFD_TMIO |
54 | bool | 63 | bool |
55 | default n | 64 | default n |
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index 03ad239ecef0..6abebe364419 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile | |||
@@ -22,3 +22,4 @@ obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o | |||
22 | ifeq ($(CONFIG_SA1100_ASSABET),y) | 22 | ifeq ($(CONFIG_SA1100_ASSABET),y) |
23 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o | 23 | obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o |
24 | endif | 24 | endif |
25 | obj-$(CONFIG_UCB1400_CORE) += ucb1400_core.o | ||
diff --git a/drivers/mfd/ucb1400_core.c b/drivers/mfd/ucb1400_core.c new file mode 100644 index 000000000000..178159e264ce --- /dev/null +++ b/drivers/mfd/ucb1400_core.c | |||
@@ -0,0 +1,106 @@ | |||
1 | /* | ||
2 | * Core functions for: | ||
3 | * Philips UCB1400 multifunction chip | ||
4 | * | ||
5 | * Based on ucb1400_ts.c: | ||
6 | * Author: Nicolas Pitre | ||
7 | * Created: September 25, 2006 | ||
8 | * Copyright: MontaVista Software, Inc. | ||
9 | * | ||
10 | * Spliting done by: Marek Vasut <marek.vasut@gmail.com> | ||
11 | * If something doesnt work and it worked before spliting, e-mail me, | ||
12 | * dont bother Nicolas please ;-) | ||
13 | * | ||
14 | * This program is free software; you can redistribute it and/or modify | ||
15 | * it under the terms of the GNU General Public License version 2 as | ||
16 | * published by the Free Software Foundation. | ||
17 | * | ||
18 | * This code is heavily based on ucb1x00-*.c copyrighted by Russell King | ||
19 | * covering the UCB1100, UCB1200 and UCB1300.. Support for the UCB1400 has | ||
20 | * been made separate from ucb1x00-core/ucb1x00-ts on Russell's request. | ||
21 | */ | ||
22 | |||
23 | #include <linux/module.h> | ||
24 | #include <linux/ucb1400.h> | ||
25 | |||
26 | static int ucb1400_core_probe(struct device *dev) | ||
27 | { | ||
28 | int err; | ||
29 | struct ucb1400 *ucb; | ||
30 | struct ucb1400_ts ucb_ts; | ||
31 | struct snd_ac97 *ac97; | ||
32 | |||
33 | memset(&ucb_ts, 0, sizeof(ucb_ts)); | ||
34 | |||
35 | ucb = kzalloc(sizeof(struct ucb1400), GFP_KERNEL); | ||
36 | if (!ucb) { | ||
37 | err = -ENOMEM; | ||
38 | goto err; | ||
39 | } | ||
40 | |||
41 | dev_set_drvdata(dev, ucb); | ||
42 | |||
43 | ac97 = to_ac97_t(dev); | ||
44 | |||
45 | ucb_ts.id = ucb1400_reg_read(ac97, UCB_ID); | ||
46 | if (ucb_ts.id != UCB_ID_1400) { | ||
47 | err = -ENODEV; | ||
48 | goto err0; | ||
49 | } | ||
50 | |||
51 | /* TOUCHSCREEN */ | ||
52 | ucb_ts.ac97 = ac97; | ||
53 | ucb->ucb1400_ts = platform_device_alloc("ucb1400_ts", -1); | ||
54 | if (!ucb->ucb1400_ts) { | ||
55 | err = -ENOMEM; | ||
56 | goto err0; | ||
57 | } | ||
58 | err = platform_device_add_data(ucb->ucb1400_ts, &ucb_ts, | ||
59 | sizeof(ucb_ts)); | ||
60 | if (err) | ||
61 | goto err1; | ||
62 | err = platform_device_add(ucb->ucb1400_ts); | ||
63 | if (err) | ||
64 | goto err1; | ||
65 | |||
66 | return 0; | ||
67 | |||
68 | err1: | ||
69 | platform_device_put(ucb->ucb1400_ts); | ||
70 | err0: | ||
71 | kfree(ucb); | ||
72 | err: | ||
73 | return err; | ||
74 | } | ||
75 | |||
76 | static int ucb1400_core_remove(struct device *dev) | ||
77 | { | ||
78 | struct ucb1400 *ucb = dev_get_drvdata(dev); | ||
79 | |||
80 | platform_device_unregister(ucb->ucb1400_ts); | ||
81 | kfree(ucb); | ||
82 | return 0; | ||
83 | } | ||
84 | |||
85 | static struct device_driver ucb1400_core_driver = { | ||
86 | .name = "ucb1400_core", | ||
87 | .bus = &ac97_bus_type, | ||
88 | .probe = ucb1400_core_probe, | ||
89 | .remove = ucb1400_core_remove, | ||
90 | }; | ||
91 | |||
92 | static int __init ucb1400_core_init(void) | ||
93 | { | ||
94 | return driver_register(&ucb1400_core_driver); | ||
95 | } | ||
96 | |||
97 | static void __exit ucb1400_core_exit(void) | ||
98 | { | ||
99 | driver_unregister(&ucb1400_core_driver); | ||
100 | } | ||
101 | |||
102 | module_init(ucb1400_core_init); | ||
103 | module_exit(ucb1400_core_exit); | ||
104 | |||
105 | MODULE_DESCRIPTION("Philips UCB1400 driver"); | ||
106 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/mmc/host/pxamci.c b/drivers/mmc/host/pxamci.c index 55093ad132ca..ebfaa9960939 100644 --- a/drivers/mmc/host/pxamci.c +++ b/drivers/mmc/host/pxamci.c | |||
@@ -520,7 +520,7 @@ static int pxamci_probe(struct platform_device *pdev) | |||
520 | /* | 520 | /* |
521 | * Block length register is only 10 bits before PXA27x. | 521 | * Block length register is only 10 bits before PXA27x. |
522 | */ | 522 | */ |
523 | mmc->max_blk_size = (cpu_is_pxa21x() || cpu_is_pxa25x()) ? 1023 : 2048; | 523 | mmc->max_blk_size = cpu_is_pxa25x() ? 1023 : 2048; |
524 | 524 | ||
525 | /* | 525 | /* |
526 | * Block count register is 16 bits. | 526 | * Block count register is 16 bits. |
@@ -554,7 +554,7 @@ static int pxamci_probe(struct platform_device *pdev) | |||
554 | MMC_VDD_32_33|MMC_VDD_33_34; | 554 | MMC_VDD_32_33|MMC_VDD_33_34; |
555 | mmc->caps = 0; | 555 | mmc->caps = 0; |
556 | host->cmdat = 0; | 556 | host->cmdat = 0; |
557 | if (!cpu_is_pxa21x() && !cpu_is_pxa25x()) { | 557 | if (!cpu_is_pxa25x()) { |
558 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; | 558 | mmc->caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ; |
559 | host->cmdat |= CMDAT_SDIO_INT_EN; | 559 | host->cmdat |= CMDAT_SDIO_INT_EN; |
560 | if (cpu_is_pxa300() || cpu_is_pxa310()) | 560 | if (cpu_is_pxa300() || cpu_is_pxa310()) |
diff --git a/drivers/mtd/nand/cmx270_nand.c b/drivers/mtd/nand/cmx270_nand.c index 9eba3f04783a..fa129c09bca8 100644 --- a/drivers/mtd/nand/cmx270_nand.c +++ b/drivers/mtd/nand/cmx270_nand.c | |||
@@ -156,7 +156,7 @@ static int cmx270_init(void) | |||
156 | int mtd_parts_nb = 0; | 156 | int mtd_parts_nb = 0; |
157 | int ret; | 157 | int ret; |
158 | 158 | ||
159 | if (!machine_is_armcore()) | 159 | if (!(machine_is_armcore() && cpu_is_pxa27x())) |
160 | return -ENODEV; | 160 | return -ENODEV; |
161 | 161 | ||
162 | ret = gpio_request(GPIO_NAND_CS, "NAND CS"); | 162 | ret = gpio_request(GPIO_NAND_CS, "NAND CS"); |
diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c index 4aa61a1a3d55..c5b02b66f756 100644 --- a/drivers/net/irda/pxaficp_ir.c +++ b/drivers/net/irda/pxaficp_ir.c | |||
@@ -572,8 +572,8 @@ static void pxa_irda_startup(struct pxa_irda *si) | |||
572 | ICCR2 = ICCR2_TXP | ICCR2_TRIG_32; | 572 | ICCR2 = ICCR2_TXP | ICCR2_TRIG_32; |
573 | 573 | ||
574 | /* configure DMAC */ | 574 | /* configure DMAC */ |
575 | DRCMR17 = si->rxdma | DRCMR_MAPVLD; | 575 | DRCMR(17) = si->rxdma | DRCMR_MAPVLD; |
576 | DRCMR18 = si->txdma | DRCMR_MAPVLD; | 576 | DRCMR(18) = si->txdma | DRCMR_MAPVLD; |
577 | 577 | ||
578 | /* force SIR reinitialization */ | 578 | /* force SIR reinitialization */ |
579 | si->speed = 4000000; | 579 | si->speed = 4000000; |
@@ -602,8 +602,8 @@ static void pxa_irda_shutdown(struct pxa_irda *si) | |||
602 | /* disable the STUART or FICP clocks */ | 602 | /* disable the STUART or FICP clocks */ |
603 | pxa_irda_disable_clk(si); | 603 | pxa_irda_disable_clk(si); |
604 | 604 | ||
605 | DRCMR17 = 0; | 605 | DRCMR(17) = 0; |
606 | DRCMR18 = 0; | 606 | DRCMR(18) = 0; |
607 | 607 | ||
608 | local_irq_restore(flags); | 608 | local_irq_restore(flags); |
609 | 609 | ||
diff --git a/drivers/net/smc91x.h b/drivers/net/smc91x.h index 8322e7f37af5..160873f0a817 100644 --- a/drivers/net/smc91x.h +++ b/drivers/net/smc91x.h | |||
@@ -43,7 +43,8 @@ | |||
43 | #if defined(CONFIG_ARCH_LUBBOCK) ||\ | 43 | #if defined(CONFIG_ARCH_LUBBOCK) ||\ |
44 | defined(CONFIG_MACH_MAINSTONE) ||\ | 44 | defined(CONFIG_MACH_MAINSTONE) ||\ |
45 | defined(CONFIG_MACH_ZYLONITE) ||\ | 45 | defined(CONFIG_MACH_ZYLONITE) ||\ |
46 | defined(CONFIG_MACH_LITTLETON) | 46 | defined(CONFIG_MACH_LITTLETON) ||\ |
47 | defined(CONFIG_ARCH_VIPER) | ||
47 | 48 | ||
48 | #include <asm/mach-types.h> | 49 | #include <asm/mach-types.h> |
49 | 50 | ||
@@ -778,14 +779,6 @@ smc_pxa_dma_irq(int dma, void *dummy) | |||
778 | #define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode | 779 | #define RPC_ANEG 0x0800 // When 1 PHY is in Auto-Negotiate Mode |
779 | #define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb | 780 | #define RPC_LSXA_SHFT 5 // Bits to shift LS2A,LS1A,LS0A to lsb |
780 | #define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb | 781 | #define RPC_LSXB_SHFT 2 // Bits to get LS2B,LS1B,LS0B to lsb |
781 | #define RPC_LED_100_10 (0x00) // LED = 100Mbps OR's with 10Mbps link detect | ||
782 | #define RPC_LED_RES (0x01) // LED = Reserved | ||
783 | #define RPC_LED_10 (0x02) // LED = 10Mbps link detect | ||
784 | #define RPC_LED_FD (0x03) // LED = Full Duplex Mode | ||
785 | #define RPC_LED_TX_RX (0x04) // LED = TX or RX packet occurred | ||
786 | #define RPC_LED_100 (0x05) // LED = 100Mbps link dectect | ||
787 | #define RPC_LED_TX (0x06) // LED = TX packet occurred | ||
788 | #define RPC_LED_RX (0x07) // LED = RX packet occurred | ||
789 | 782 | ||
790 | #ifndef RPC_LSA_DEFAULT | 783 | #ifndef RPC_LSA_DEFAULT |
791 | #define RPC_LSA_DEFAULT RPC_LED_100 | 784 | #define RPC_LSA_DEFAULT RPC_LED_100 |
diff --git a/drivers/pcmcia/Kconfig b/drivers/pcmcia/Kconfig index e0f884034c9f..f57eeae3830a 100644 --- a/drivers/pcmcia/Kconfig +++ b/drivers/pcmcia/Kconfig | |||
@@ -220,7 +220,8 @@ config PCMCIA_PXA2XX | |||
220 | tristate "PXA2xx support" | 220 | tristate "PXA2xx support" |
221 | depends on ARM && ARCH_PXA && PCMCIA | 221 | depends on ARM && ARCH_PXA && PCMCIA |
222 | depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ | 222 | depends on (ARCH_LUBBOCK || MACH_MAINSTONE || PXA_SHARPSL \ |
223 | || MACH_ARMCORE || ARCH_PXA_PALM) | 223 | || MACH_ARMCORE || ARCH_PXA_PALM || TRIZEPS_PCMCIA \ |
224 | || ARCH_VIPER) | ||
224 | help | 225 | help |
225 | Say Y here to include support for the PXA2xx PCMCIA controller | 226 | Say Y here to include support for the PXA2xx PCMCIA controller |
226 | 227 | ||
diff --git a/drivers/pcmcia/Makefile b/drivers/pcmcia/Makefile index 269a9e913ba2..a87902de8d3b 100644 --- a/drivers/pcmcia/Makefile +++ b/drivers/pcmcia/Makefile | |||
@@ -29,7 +29,6 @@ obj-$(CONFIG_PCMCIA_M8XX) += m8xx_pcmcia.o | |||
29 | obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o | 29 | obj-$(CONFIG_HD64465_PCMCIA) += hd64465_ss.o |
30 | obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o | 30 | obj-$(CONFIG_PCMCIA_SA1100) += sa11xx_core.o sa1100_cs.o |
31 | obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o | 31 | obj-$(CONFIG_PCMCIA_SA1111) += sa11xx_core.o sa1111_cs.o |
32 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_core.o pxa2xx_cs.o | ||
33 | obj-$(CONFIG_M32R_PCC) += m32r_pcc.o | 32 | obj-$(CONFIG_M32R_PCC) += m32r_pcc.o |
34 | obj-$(CONFIG_M32R_CFC) += m32r_cfc.o | 33 | obj-$(CONFIG_M32R_CFC) += m32r_cfc.o |
35 | obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o | 34 | obj-$(CONFIG_PCMCIA_AU1X00) += au1x00_ss.o |
@@ -68,9 +67,14 @@ sa1100_cs-$(CONFIG_SA1100_H3600) += sa1100_h3600.o | |||
68 | sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o | 67 | sa1100_cs-$(CONFIG_SA1100_SHANNON) += sa1100_shannon.o |
69 | sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o | 68 | sa1100_cs-$(CONFIG_SA1100_SIMPAD) += sa1100_simpad.o |
70 | 69 | ||
71 | pxa2xx_cs-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock.o sa1111_generic.o | 70 | pxa2xx_lubbock_cs-y += pxa2xx_lubbock.o sa1111_generic.o |
72 | pxa2xx_cs-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o | 71 | pxa2xx-obj-$(CONFIG_ARCH_LUBBOCK) += pxa2xx_lubbock_cs.o |
73 | pxa2xx_cs-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o | 72 | pxa2xx-obj-$(CONFIG_MACH_MAINSTONE) += pxa2xx_mainstone.o |
74 | pxa2xx_cs-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x270.o | 73 | pxa2xx-obj-$(CONFIG_PXA_SHARPSL) += pxa2xx_sharpsl.o |
75 | pxa2xx_cs-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o | 74 | pxa2xx-obj-$(CONFIG_MACH_ARMCORE) += pxa2xx_cm_x2xx.o pxa2xx_cm_x255.o pxa2xx_cm_x270.o |
75 | pxa2xx-obj-$(CONFIG_ARCH_VIPER) += pxa2xx_viper.o | ||
76 | pxa2xx-obj-$(CONFIG_TRIZEPS_PCMCIA) += pxa2xx_trizeps.o | ||
77 | pxa2xx-obj-$(CONFIG_MACH_PALMTX) += pxa2xx_palmtx.o | ||
78 | pxa2xx-obj-$(CONFIG_MACH_PALMLD) += pxa2xx_palmld.o | ||
76 | 79 | ||
80 | obj-$(CONFIG_PCMCIA_PXA2XX) += pxa2xx_core.o $(pxa2xx-obj-y) | ||
diff --git a/drivers/pcmcia/pxa2xx_base.c b/drivers/pcmcia/pxa2xx_base.c index 1b07af5a2ed3..13f1e0fd3f31 100644 --- a/drivers/pcmcia/pxa2xx_base.c +++ b/drivers/pcmcia/pxa2xx_base.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <asm/system.h> | 30 | #include <asm/system.h> |
31 | #include <mach/pxa-regs.h> | 31 | #include <mach/pxa-regs.h> |
32 | #include <mach/pxa2xx-regs.h> | 32 | #include <mach/pxa2xx-regs.h> |
33 | #include <asm/mach-types.h> | ||
33 | 34 | ||
34 | #include <pcmcia/cs_types.h> | 35 | #include <pcmcia/cs_types.h> |
35 | #include <pcmcia/ss.h> | 36 | #include <pcmcia/ss.h> |
@@ -166,18 +167,32 @@ pxa2xx_pcmcia_frequency_change(struct soc_pcmcia_socket *skt, | |||
166 | } | 167 | } |
167 | #endif | 168 | #endif |
168 | 169 | ||
170 | static void pxa2xx_configure_sockets(struct device *dev) | ||
171 | { | ||
172 | struct pcmcia_low_level *ops = dev->platform_data; | ||
173 | |||
174 | /* | ||
175 | * We have at least one socket, so set MECR:CIT | ||
176 | * (Card Is There) | ||
177 | */ | ||
178 | MECR |= MECR_CIT; | ||
179 | |||
180 | /* Set MECR:NOS (Number Of Sockets) */ | ||
181 | if (ops->nr > 1 || machine_is_viper()) | ||
182 | MECR |= MECR_NOS; | ||
183 | else | ||
184 | MECR &= ~MECR_NOS; | ||
185 | } | ||
186 | |||
169 | int __pxa2xx_drv_pcmcia_probe(struct device *dev) | 187 | int __pxa2xx_drv_pcmcia_probe(struct device *dev) |
170 | { | 188 | { |
171 | int ret; | 189 | int ret; |
172 | struct pcmcia_low_level *ops; | 190 | struct pcmcia_low_level *ops; |
173 | int first, nr; | ||
174 | 191 | ||
175 | if (!dev || !dev->platform_data) | 192 | if (!dev || !dev->platform_data) |
176 | return -ENODEV; | 193 | return -ENODEV; |
177 | 194 | ||
178 | ops = (struct pcmcia_low_level *)dev->platform_data; | 195 | ops = (struct pcmcia_low_level *)dev->platform_data; |
179 | first = ops->first; | ||
180 | nr = ops->nr; | ||
181 | 196 | ||
182 | /* Provide our PXA2xx specific timing routines. */ | 197 | /* Provide our PXA2xx specific timing routines. */ |
183 | ops->set_timing = pxa2xx_pcmcia_set_timing; | 198 | ops->set_timing = pxa2xx_pcmcia_set_timing; |
@@ -185,21 +200,10 @@ int __pxa2xx_drv_pcmcia_probe(struct device *dev) | |||
185 | ops->frequency_change = pxa2xx_pcmcia_frequency_change; | 200 | ops->frequency_change = pxa2xx_pcmcia_frequency_change; |
186 | #endif | 201 | #endif |
187 | 202 | ||
188 | ret = soc_common_drv_pcmcia_probe(dev, ops, first, nr); | 203 | ret = soc_common_drv_pcmcia_probe(dev, ops, ops->first, ops->nr); |
189 | 204 | ||
190 | if (ret == 0) { | 205 | if (!ret) |
191 | /* | 206 | pxa2xx_configure_sockets(dev); |
192 | * We have at least one socket, so set MECR:CIT | ||
193 | * (Card Is There) | ||
194 | */ | ||
195 | MECR |= MECR_CIT; | ||
196 | |||
197 | /* Set MECR:NOS (Number Of Sockets) */ | ||
198 | if (nr > 1) | ||
199 | MECR |= MECR_NOS; | ||
200 | else | ||
201 | MECR &= ~MECR_NOS; | ||
202 | } | ||
203 | 207 | ||
204 | return ret; | 208 | return ret; |
205 | } | 209 | } |
@@ -223,11 +227,7 @@ static int pxa2xx_drv_pcmcia_suspend(struct platform_device *dev, pm_message_t s | |||
223 | 227 | ||
224 | static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev) | 228 | static int pxa2xx_drv_pcmcia_resume(struct platform_device *dev) |
225 | { | 229 | { |
226 | struct pcmcia_low_level *ops = dev->dev.platform_data; | 230 | pxa2xx_configure_sockets(&dev->dev); |
227 | int nr = ops ? ops->nr : 0; | ||
228 | |||
229 | MECR = nr > 1 ? MECR_CIT | MECR_NOS : (nr > 0 ? MECR_CIT : 0); | ||
230 | |||
231 | return pcmcia_socket_dev_resume(&dev->dev); | 231 | return pcmcia_socket_dev_resume(&dev->dev); |
232 | } | 232 | } |
233 | 233 | ||
diff --git a/drivers/pcmcia/pxa2xx_cm_x255.c b/drivers/pcmcia/pxa2xx_cm_x255.c new file mode 100644 index 000000000000..7c8bcb476622 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_cm_x255.c | |||
@@ -0,0 +1,154 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa/pxa_cm_x255.c | ||
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 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Compulab Ltd., 2003, 2007, 2008 | ||
9 | * Mike Rapoport <mike@compulab.co.il> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/platform_device.h> | ||
14 | #include <linux/irq.h> | ||
15 | #include <linux/delay.h> | ||
16 | #include <linux/gpio.h> | ||
17 | |||
18 | #include <asm/mach-types.h> | ||
19 | #include <mach/pxa-regs.h> | ||
20 | |||
21 | #include "soc_common.h" | ||
22 | |||
23 | #define GPIO_PCMCIA_SKTSEL (54) | ||
24 | #define GPIO_PCMCIA_S0_CD_VALID (16) | ||
25 | #define GPIO_PCMCIA_S1_CD_VALID (17) | ||
26 | #define GPIO_PCMCIA_S0_RDYINT (6) | ||
27 | #define GPIO_PCMCIA_S1_RDYINT (8) | ||
28 | #define GPIO_PCMCIA_RESET (9) | ||
29 | |||
30 | #define PCMCIA_S0_CD_VALID IRQ_GPIO(GPIO_PCMCIA_S0_CD_VALID) | ||
31 | #define PCMCIA_S1_CD_VALID IRQ_GPIO(GPIO_PCMCIA_S1_CD_VALID) | ||
32 | #define PCMCIA_S0_RDYINT IRQ_GPIO(GPIO_PCMCIA_S0_RDYINT) | ||
33 | #define PCMCIA_S1_RDYINT IRQ_GPIO(GPIO_PCMCIA_S1_RDYINT) | ||
34 | |||
35 | |||
36 | static struct pcmcia_irqs irqs[] = { | ||
37 | { 0, PCMCIA_S0_CD_VALID, "PCMCIA0 CD" }, | ||
38 | { 1, PCMCIA_S1_CD_VALID, "PCMCIA1 CD" }, | ||
39 | }; | ||
40 | |||
41 | static int cmx255_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
42 | { | ||
43 | int ret = gpio_request(GPIO_PCMCIA_RESET, "PCCard reset"); | ||
44 | if (ret) | ||
45 | return ret; | ||
46 | gpio_direction_output(GPIO_PCMCIA_RESET, 0); | ||
47 | |||
48 | skt->irq = skt->nr == 0 ? PCMCIA_S0_RDYINT : PCMCIA_S1_RDYINT; | ||
49 | ret = soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
50 | if (!ret) | ||
51 | gpio_free(GPIO_PCMCIA_RESET); | ||
52 | |||
53 | return ret; | ||
54 | } | ||
55 | |||
56 | static void cmx255_pcmcia_shutdown(struct soc_pcmcia_socket *skt) | ||
57 | { | ||
58 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
59 | gpio_free(GPIO_PCMCIA_RESET); | ||
60 | } | ||
61 | |||
62 | |||
63 | static void cmx255_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
64 | struct pcmcia_state *state) | ||
65 | { | ||
66 | int cd = skt->nr ? GPIO_PCMCIA_S1_CD_VALID : GPIO_PCMCIA_S0_CD_VALID; | ||
67 | int rdy = skt->nr ? GPIO_PCMCIA_S0_RDYINT : GPIO_PCMCIA_S1_RDYINT; | ||
68 | |||
69 | state->detect = !gpio_get_value(cd); | ||
70 | state->ready = !!gpio_get_value(rdy); | ||
71 | state->bvd1 = 1; | ||
72 | state->bvd2 = 1; | ||
73 | state->vs_3v = 0; | ||
74 | state->vs_Xv = 0; | ||
75 | state->wrprot = 0; /* not available */ | ||
76 | } | ||
77 | |||
78 | |||
79 | static int cmx255_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
80 | const socket_state_t *state) | ||
81 | { | ||
82 | switch (skt->nr) { | ||
83 | case 0: | ||
84 | if (state->flags & SS_RESET) { | ||
85 | gpio_set_value(GPIO_PCMCIA_SKTSEL, 0); | ||
86 | udelay(1); | ||
87 | gpio_set_value(GPIO_PCMCIA_RESET, 1); | ||
88 | udelay(10); | ||
89 | gpio_set_value(GPIO_PCMCIA_RESET, 0); | ||
90 | } | ||
91 | break; | ||
92 | case 1: | ||
93 | if (state->flags & SS_RESET) { | ||
94 | gpio_set_value(GPIO_PCMCIA_SKTSEL, 1); | ||
95 | udelay(1); | ||
96 | gpio_set_value(GPIO_PCMCIA_RESET, 1); | ||
97 | udelay(10); | ||
98 | gpio_set_value(GPIO_PCMCIA_RESET, 0); | ||
99 | } | ||
100 | break; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
105 | |||
106 | static void cmx255_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
107 | { | ||
108 | } | ||
109 | |||
110 | static void cmx255_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
111 | { | ||
112 | } | ||
113 | |||
114 | |||
115 | static struct pcmcia_low_level cmx255_pcmcia_ops __initdata = { | ||
116 | .owner = THIS_MODULE, | ||
117 | .hw_init = cmx255_pcmcia_hw_init, | ||
118 | .hw_shutdown = cmx255_pcmcia_shutdown, | ||
119 | .socket_state = cmx255_pcmcia_socket_state, | ||
120 | .configure_socket = cmx255_pcmcia_configure_socket, | ||
121 | .socket_init = cmx255_pcmcia_socket_init, | ||
122 | .socket_suspend = cmx255_pcmcia_socket_suspend, | ||
123 | .nr = 1, | ||
124 | }; | ||
125 | |||
126 | static struct platform_device *cmx255_pcmcia_device; | ||
127 | |||
128 | int __init cmx255_pcmcia_init(void) | ||
129 | { | ||
130 | int ret; | ||
131 | |||
132 | cmx255_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); | ||
133 | |||
134 | if (!cmx255_pcmcia_device) | ||
135 | return -ENOMEM; | ||
136 | |||
137 | ret = platform_device_add_data(cmx255_pcmcia_device, &cmx255_pcmcia_ops, | ||
138 | sizeof(cmx255_pcmcia_ops)); | ||
139 | |||
140 | if (ret == 0) { | ||
141 | printk(KERN_INFO "Registering cm-x255 PCMCIA interface.\n"); | ||
142 | ret = platform_device_add(cmx255_pcmcia_device); | ||
143 | } | ||
144 | |||
145 | if (ret) | ||
146 | platform_device_put(cmx255_pcmcia_device); | ||
147 | |||
148 | return ret; | ||
149 | } | ||
150 | |||
151 | void __exit cmx255_pcmcia_exit(void) | ||
152 | { | ||
153 | platform_device_unregister(cmx255_pcmcia_device); | ||
154 | } | ||
diff --git a/drivers/pcmcia/pxa2xx_cm_x270.c b/drivers/pcmcia/pxa2xx_cm_x270.c index bcff5cfed051..6c3aac377126 100644 --- a/drivers/pcmcia/pxa2xx_cm_x270.c +++ b/drivers/pcmcia/pxa2xx_cm_x270.c | |||
@@ -105,13 +105,10 @@ static struct pcmcia_low_level cmx270_pcmcia_ops __initdata = { | |||
105 | 105 | ||
106 | static struct platform_device *cmx270_pcmcia_device; | 106 | static struct platform_device *cmx270_pcmcia_device; |
107 | 107 | ||
108 | static int __init cmx270_pcmcia_init(void) | 108 | int __init cmx270_pcmcia_init(void) |
109 | { | 109 | { |
110 | int ret; | 110 | int ret; |
111 | 111 | ||
112 | if (!machine_is_armcore()) | ||
113 | return -ENODEV; | ||
114 | |||
115 | cmx270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); | 112 | cmx270_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); |
116 | 113 | ||
117 | if (!cmx270_pcmcia_device) | 114 | if (!cmx270_pcmcia_device) |
@@ -131,14 +128,7 @@ static int __init cmx270_pcmcia_init(void) | |||
131 | return ret; | 128 | return ret; |
132 | } | 129 | } |
133 | 130 | ||
134 | static void __exit cmx270_pcmcia_exit(void) | 131 | void __exit cmx270_pcmcia_exit(void) |
135 | { | 132 | { |
136 | platform_device_unregister(cmx270_pcmcia_device); | 133 | platform_device_unregister(cmx270_pcmcia_device); |
137 | } | 134 | } |
138 | |||
139 | module_init(cmx270_pcmcia_init); | ||
140 | module_exit(cmx270_pcmcia_exit); | ||
141 | |||
142 | MODULE_LICENSE("GPL"); | ||
143 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | ||
144 | MODULE_DESCRIPTION("CM-x270 PCMCIA driver"); | ||
diff --git a/drivers/pcmcia/pxa2xx_cm_x2xx.c b/drivers/pcmcia/pxa2xx_cm_x2xx.c new file mode 100644 index 000000000000..4f09506ad8d4 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_cm_x2xx.c | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa/pxa_cm_x2xx.c | ||
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 as | ||
6 | * published by the Free Software Foundation. | ||
7 | * | ||
8 | * Compulab Ltd., 2003, 2007, 2008 | ||
9 | * Mike Rapoport <mike@compulab.co.il> | ||
10 | * | ||
11 | */ | ||
12 | |||
13 | #include <linux/module.h> | ||
14 | |||
15 | #include <asm/system.h> | ||
16 | #include <asm/mach-types.h> | ||
17 | #include <mach/system.h> | ||
18 | |||
19 | int cmx255_pcmcia_init(void); | ||
20 | int cmx270_pcmcia_init(void); | ||
21 | void cmx255_pcmcia_exit(void); | ||
22 | void cmx270_pcmcia_exit(void); | ||
23 | |||
24 | static int __init cmx2xx_pcmcia_init(void) | ||
25 | { | ||
26 | int ret = -ENODEV; | ||
27 | |||
28 | if (machine_is_armcore() && cpu_is_pxa25x()) | ||
29 | ret = cmx255_pcmcia_init(); | ||
30 | else if (machine_is_armcore() && cpu_is_pxa27x()) | ||
31 | ret = cmx270_pcmcia_init(); | ||
32 | |||
33 | return ret; | ||
34 | } | ||
35 | |||
36 | static void __exit cmx2xx_pcmcia_exit(void) | ||
37 | { | ||
38 | if (machine_is_armcore() && cpu_is_pxa25x()) | ||
39 | cmx255_pcmcia_exit(); | ||
40 | else if (machine_is_armcore() && cpu_is_pxa27x()) | ||
41 | cmx270_pcmcia_exit(); | ||
42 | } | ||
43 | |||
44 | module_init(cmx2xx_pcmcia_init); | ||
45 | module_exit(cmx2xx_pcmcia_exit); | ||
46 | |||
47 | MODULE_LICENSE("GPL"); | ||
48 | MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>"); | ||
49 | MODULE_DESCRIPTION("CM-x2xx PCMCIA driver"); | ||
diff --git a/drivers/pcmcia/pxa2xx_palmld.c b/drivers/pcmcia/pxa2xx_palmld.c new file mode 100644 index 000000000000..1736c67e547e --- /dev/null +++ b/drivers/pcmcia/pxa2xx_palmld.c | |||
@@ -0,0 +1,151 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa2xx_palmld.c | ||
3 | * | ||
4 | * Driver for Palm LifeDrive PCMCIA | ||
5 | * | ||
6 | * Copyright (C) 2006 Alex Osborne <ato@meshy.org> | ||
7 | * Copyright (C) 2007-2008 Marek Vasut <marek.vasut@gmail.com> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License version 2 as | ||
11 | * published by the Free Software Foundation. | ||
12 | * | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/platform_device.h> | ||
17 | #include <linux/gpio.h> | ||
18 | |||
19 | #include <asm/mach-types.h> | ||
20 | #include <mach/palmld.h> | ||
21 | #include "soc_common.h" | ||
22 | |||
23 | static int palmld_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
24 | { | ||
25 | int ret; | ||
26 | |||
27 | ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_POWER, "PCMCIA PWR"); | ||
28 | if (ret) | ||
29 | goto err1; | ||
30 | ret = gpio_direction_output(GPIO_NR_PALMLD_PCMCIA_POWER, 0); | ||
31 | if (ret) | ||
32 | goto err2; | ||
33 | |||
34 | ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_RESET, "PCMCIA RST"); | ||
35 | if (ret) | ||
36 | goto err2; | ||
37 | ret = gpio_direction_output(GPIO_NR_PALMLD_PCMCIA_RESET, 1); | ||
38 | if (ret) | ||
39 | goto err3; | ||
40 | |||
41 | ret = gpio_request(GPIO_NR_PALMLD_PCMCIA_READY, "PCMCIA RDY"); | ||
42 | if (ret) | ||
43 | goto err3; | ||
44 | ret = gpio_direction_input(GPIO_NR_PALMLD_PCMCIA_READY); | ||
45 | if (ret) | ||
46 | goto err4; | ||
47 | |||
48 | skt->irq = IRQ_GPIO(GPIO_NR_PALMLD_PCMCIA_READY); | ||
49 | return 0; | ||
50 | |||
51 | err4: | ||
52 | gpio_free(GPIO_NR_PALMLD_PCMCIA_READY); | ||
53 | err3: | ||
54 | gpio_free(GPIO_NR_PALMLD_PCMCIA_RESET); | ||
55 | err2: | ||
56 | gpio_free(GPIO_NR_PALMLD_PCMCIA_POWER); | ||
57 | err1: | ||
58 | return ret; | ||
59 | } | ||
60 | |||
61 | static void palmld_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
62 | { | ||
63 | gpio_free(GPIO_NR_PALMLD_PCMCIA_READY); | ||
64 | gpio_free(GPIO_NR_PALMLD_PCMCIA_RESET); | ||
65 | gpio_free(GPIO_NR_PALMLD_PCMCIA_POWER); | ||
66 | } | ||
67 | |||
68 | static void palmld_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
69 | struct pcmcia_state *state) | ||
70 | { | ||
71 | state->detect = 1; /* always inserted */ | ||
72 | state->ready = !!gpio_get_value(GPIO_NR_PALMLD_PCMCIA_READY); | ||
73 | state->bvd1 = 1; | ||
74 | state->bvd2 = 1; | ||
75 | state->wrprot = 0; | ||
76 | state->vs_3v = 1; | ||
77 | state->vs_Xv = 0; | ||
78 | } | ||
79 | |||
80 | static int palmld_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
81 | const socket_state_t *state) | ||
82 | { | ||
83 | gpio_set_value(GPIO_NR_PALMLD_PCMCIA_POWER, 1); | ||
84 | gpio_set_value(GPIO_NR_PALMLD_PCMCIA_RESET, | ||
85 | !!(state->flags & SS_RESET)); | ||
86 | |||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | static void palmld_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
91 | { | ||
92 | } | ||
93 | |||
94 | static void palmld_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
95 | { | ||
96 | } | ||
97 | |||
98 | static struct pcmcia_low_level palmld_pcmcia_ops = { | ||
99 | .owner = THIS_MODULE, | ||
100 | |||
101 | .first = 0, | ||
102 | .nr = 2, | ||
103 | |||
104 | .hw_init = palmld_pcmcia_hw_init, | ||
105 | .hw_shutdown = palmld_pcmcia_hw_shutdown, | ||
106 | |||
107 | .socket_state = palmld_pcmcia_socket_state, | ||
108 | .configure_socket = palmld_pcmcia_configure_socket, | ||
109 | |||
110 | .socket_init = palmld_pcmcia_socket_init, | ||
111 | .socket_suspend = palmld_pcmcia_socket_suspend, | ||
112 | }; | ||
113 | |||
114 | static struct platform_device *palmld_pcmcia_device; | ||
115 | |||
116 | static int __init palmld_pcmcia_init(void) | ||
117 | { | ||
118 | int ret; | ||
119 | |||
120 | if (!machine_is_palmld()) | ||
121 | return -ENODEV; | ||
122 | |||
123 | palmld_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); | ||
124 | if (!palmld_pcmcia_device) | ||
125 | return -ENOMEM; | ||
126 | |||
127 | ret = platform_device_add_data(palmld_pcmcia_device, &palmld_pcmcia_ops, | ||
128 | sizeof(palmld_pcmcia_ops)); | ||
129 | |||
130 | if (!ret) | ||
131 | ret = platform_device_add(palmld_pcmcia_device); | ||
132 | |||
133 | if (ret) | ||
134 | platform_device_put(palmld_pcmcia_device); | ||
135 | |||
136 | return ret; | ||
137 | } | ||
138 | |||
139 | static void __exit palmld_pcmcia_exit(void) | ||
140 | { | ||
141 | platform_device_unregister(palmld_pcmcia_device); | ||
142 | } | ||
143 | |||
144 | module_init(palmld_pcmcia_init); | ||
145 | module_exit(palmld_pcmcia_exit); | ||
146 | |||
147 | MODULE_AUTHOR("Alex Osborne <ato@meshy.org>," | ||
148 | " Marek Vasut <marek.vasut@gmail.com>"); | ||
149 | MODULE_DESCRIPTION("PCMCIA support for Palm LifeDrive"); | ||
150 | MODULE_ALIAS("platform:pxa2xx-pcmcia"); | ||
151 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/pcmcia/pxa2xx_trizeps4.c b/drivers/pcmcia/pxa2xx_trizeps4.c new file mode 100644 index 000000000000..36c7a0b324d2 --- /dev/null +++ b/drivers/pcmcia/pxa2xx_trizeps4.c | |||
@@ -0,0 +1,256 @@ | |||
1 | /* | ||
2 | * linux/drivers/pcmcia/pxa2xx_trizeps4.c | ||
3 | * | ||
4 | * TRIZEPS PCMCIA specific routines. | ||
5 | * | ||
6 | * Author: Jürgen Schindele | ||
7 | * Created: 20 02, 2006 | ||
8 | * Copyright: Jürgen Schindele | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | */ | ||
14 | |||
15 | #include <linux/module.h> | ||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/gpio.h> | ||
19 | #include <linux/interrupt.h> | ||
20 | #include <linux/platform_device.h> | ||
21 | |||
22 | #include <asm/mach-types.h> | ||
23 | #include <asm/irq.h> | ||
24 | |||
25 | #include <mach/hardware.h> | ||
26 | #include <mach/pxa-regs.h> | ||
27 | #include <mach/trizeps4.h> | ||
28 | |||
29 | #include "soc_common.h" | ||
30 | |||
31 | extern void board_pcmcia_power(int power); | ||
32 | |||
33 | static struct pcmcia_irqs irqs[] = { | ||
34 | { 0, IRQ_GPIO(GPIO_PCD), "cs0_cd" } | ||
35 | /* on other baseboards we can have more inputs */ | ||
36 | }; | ||
37 | |||
38 | static int trizeps_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
39 | { | ||
40 | int ret, i; | ||
41 | /* we dont have voltage/card/ready detection | ||
42 | * so we dont need interrupts for it | ||
43 | */ | ||
44 | switch (skt->nr) { | ||
45 | case 0: | ||
46 | if (gpio_request(GPIO_PRDY, "cf_irq") < 0) { | ||
47 | pr_err("%s: sock %d unable to request gpio %d\n", __func__, | ||
48 | skt->nr, GPIO_PRDY); | ||
49 | return -EBUSY; | ||
50 | } | ||
51 | if (gpio_direction_input(GPIO_PRDY) < 0) { | ||
52 | pr_err("%s: sock %d unable to set input gpio %d\n", __func__, | ||
53 | skt->nr, GPIO_PRDY); | ||
54 | gpio_free(GPIO_PRDY); | ||
55 | return -EINVAL; | ||
56 | } | ||
57 | skt->irq = IRQ_GPIO(GPIO_PRDY); | ||
58 | break; | ||
59 | |||
60 | #ifndef CONFIG_MACH_TRIZEPS_CONXS | ||
61 | case 1: | ||
62 | #endif | ||
63 | default: | ||
64 | break; | ||
65 | } | ||
66 | /* release the reset of this card */ | ||
67 | pr_debug("%s: sock %d irq %d\n", __func__, skt->nr, skt->irq); | ||
68 | |||
69 | /* supplementory irqs for the socket */ | ||
70 | for (i = 0; i < ARRAY_SIZE(irqs); i++) { | ||
71 | if (irqs[i].sock != skt->nr) | ||
72 | continue; | ||
73 | if (gpio_request(IRQ_TO_GPIO(irqs[i].irq), irqs[i].str) < 0) { | ||
74 | pr_err("%s: sock %d unable to request gpio %d\n", | ||
75 | __func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq)); | ||
76 | ret = -EBUSY; | ||
77 | goto error; | ||
78 | } | ||
79 | if (gpio_direction_input(IRQ_TO_GPIO(irqs[i].irq)) < 0) { | ||
80 | pr_err("%s: sock %d unable to set input gpio %d\n", | ||
81 | __func__, skt->nr, IRQ_TO_GPIO(irqs[i].irq)); | ||
82 | ret = -EINVAL; | ||
83 | goto error; | ||
84 | } | ||
85 | } | ||
86 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
87 | |||
88 | error: | ||
89 | for (; i >= 0; i--) { | ||
90 | gpio_free(IRQ_TO_GPIO(irqs[i].irq)); | ||
91 | } | ||
92 | return (ret); | ||
93 | } | ||
94 | |||
95 | static void trizeps_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
96 | { | ||
97 | int i; | ||
98 | /* free allocated gpio's */ | ||
99 | gpio_free(GPIO_PRDY); | ||
100 | for (i = 0; i < ARRAY_SIZE(irqs); i++) | ||
101 | gpio_free(IRQ_TO_GPIO(irqs[i].irq)); | ||
102 | } | ||
103 | |||
104 | static unsigned long trizeps_pcmcia_status[2]; | ||
105 | |||
106 | static void trizeps_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
107 | struct pcmcia_state *state) | ||
108 | { | ||
109 | unsigned short status = 0, change; | ||
110 | status = CFSR_readw(); | ||
111 | change = (status ^ trizeps_pcmcia_status[skt->nr]) & | ||
112 | ConXS_CFSR_BVD_MASK; | ||
113 | if (change) { | ||
114 | trizeps_pcmcia_status[skt->nr] = status; | ||
115 | if (status & ConXS_CFSR_BVD1) { | ||
116 | /* enable_irq empty */ | ||
117 | } else { | ||
118 | /* disable_irq empty */ | ||
119 | } | ||
120 | } | ||
121 | |||
122 | switch (skt->nr) { | ||
123 | case 0: | ||
124 | /* just fill in fix states */ | ||
125 | state->detect = gpio_get_value(GPIO_PCD) ? 0 : 1; | ||
126 | state->ready = gpio_get_value(GPIO_PRDY) ? 1 : 0; | ||
127 | state->bvd1 = (status & ConXS_CFSR_BVD1) ? 1 : 0; | ||
128 | state->bvd2 = (status & ConXS_CFSR_BVD2) ? 1 : 0; | ||
129 | state->vs_3v = (status & ConXS_CFSR_VS1) ? 0 : 1; | ||
130 | state->vs_Xv = (status & ConXS_CFSR_VS2) ? 0 : 1; | ||
131 | state->wrprot = 0; /* not available */ | ||
132 | break; | ||
133 | |||
134 | #ifndef CONFIG_MACH_TRIZEPS_CONXS | ||
135 | /* on ConXS we only have one slot. Second is inactive */ | ||
136 | case 1: | ||
137 | state->detect = 0; | ||
138 | state->ready = 0; | ||
139 | state->bvd1 = 0; | ||
140 | state->bvd2 = 0; | ||
141 | state->vs_3v = 0; | ||
142 | state->vs_Xv = 0; | ||
143 | state->wrprot = 0; | ||
144 | break; | ||
145 | |||
146 | #endif | ||
147 | } | ||
148 | } | ||
149 | |||
150 | static int trizeps_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
151 | const socket_state_t *state) | ||
152 | { | ||
153 | int ret = 0; | ||
154 | unsigned short power = 0; | ||
155 | |||
156 | /* we do nothing here just check a bit */ | ||
157 | switch (state->Vcc) { | ||
158 | case 0: power &= 0xfc; break; | ||
159 | case 33: power |= ConXS_BCR_S0_VCC_3V3; break; | ||
160 | case 50: | ||
161 | pr_err("%s(): Vcc 5V not supported in socket\n", __func__); | ||
162 | break; | ||
163 | default: | ||
164 | pr_err("%s(): bad Vcc %u\n", __func__, state->Vcc); | ||
165 | ret = -1; | ||
166 | } | ||
167 | |||
168 | switch (state->Vpp) { | ||
169 | case 0: power &= 0xf3; break; | ||
170 | case 33: power |= ConXS_BCR_S0_VPP_3V3; break; | ||
171 | case 120: | ||
172 | pr_err("%s(): Vpp 12V not supported in socket\n", __func__); | ||
173 | break; | ||
174 | default: | ||
175 | if (state->Vpp != state->Vcc) { | ||
176 | pr_err("%s(): bad Vpp %u\n", __func__, state->Vpp); | ||
177 | ret = -1; | ||
178 | } | ||
179 | } | ||
180 | |||
181 | switch (skt->nr) { | ||
182 | case 0: /* we only have 3.3V */ | ||
183 | board_pcmcia_power(power); | ||
184 | break; | ||
185 | |||
186 | #ifndef CONFIG_MACH_TRIZEPS_CONXS | ||
187 | /* on ConXS we only have one slot. Second is inactive */ | ||
188 | case 1: | ||
189 | #endif | ||
190 | default: | ||
191 | break; | ||
192 | } | ||
193 | |||
194 | return ret; | ||
195 | } | ||
196 | |||
197 | static void trizeps_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
198 | { | ||
199 | /* default is on */ | ||
200 | board_pcmcia_power(0x9); | ||
201 | } | ||
202 | |||
203 | static void trizeps_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
204 | { | ||
205 | board_pcmcia_power(0x0); | ||
206 | } | ||
207 | |||
208 | static struct pcmcia_low_level trizeps_pcmcia_ops = { | ||
209 | .owner = THIS_MODULE, | ||
210 | .hw_init = trizeps_pcmcia_hw_init, | ||
211 | .hw_shutdown = trizeps_pcmcia_hw_shutdown, | ||
212 | .socket_state = trizeps_pcmcia_socket_state, | ||
213 | .configure_socket = trizeps_pcmcia_configure_socket, | ||
214 | .socket_init = trizeps_pcmcia_socket_init, | ||
215 | .socket_suspend = trizeps_pcmcia_socket_suspend, | ||
216 | #ifdef CONFIG_MACH_TRIZEPS_CONXS | ||
217 | .nr = 1, | ||
218 | #else | ||
219 | .nr = 2, | ||
220 | #endif | ||
221 | .first = 0, | ||
222 | }; | ||
223 | |||
224 | static struct platform_device *trizeps_pcmcia_device; | ||
225 | |||
226 | static int __init trizeps_pcmcia_init(void) | ||
227 | { | ||
228 | int ret; | ||
229 | |||
230 | trizeps_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); | ||
231 | if (!trizeps_pcmcia_device) | ||
232 | return -ENOMEM; | ||
233 | |||
234 | ret = platform_device_add_data(trizeps_pcmcia_device, | ||
235 | &trizeps_pcmcia_ops, sizeof(trizeps_pcmcia_ops)); | ||
236 | |||
237 | if (ret == 0) | ||
238 | ret = platform_device_add(trizeps_pcmcia_device); | ||
239 | |||
240 | if (ret) | ||
241 | platform_device_put(trizeps_pcmcia_device); | ||
242 | |||
243 | return ret; | ||
244 | } | ||
245 | |||
246 | static void __exit trizeps_pcmcia_exit(void) | ||
247 | { | ||
248 | platform_device_unregister(trizeps_pcmcia_device); | ||
249 | } | ||
250 | |||
251 | fs_initcall(trizeps_pcmcia_init); | ||
252 | module_exit(trizeps_pcmcia_exit); | ||
253 | |||
254 | MODULE_LICENSE("GPL"); | ||
255 | MODULE_AUTHOR("Juergen Schindele"); | ||
256 | MODULE_ALIAS("platform:pxa2xx-pcmcia"); | ||
diff --git a/drivers/pcmcia/pxa2xx_viper.c b/drivers/pcmcia/pxa2xx_viper.c new file mode 100644 index 000000000000..dd10481be7bf --- /dev/null +++ b/drivers/pcmcia/pxa2xx_viper.c | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * VIPER PCMCIA support | ||
3 | * Copyright 2004 Arcom Control Systems | ||
4 | * | ||
5 | * Maintained by Marc Zyngier <maz@misterjones.org> | ||
6 | * <marc.zyngier@altran.com> | ||
7 | * | ||
8 | * Based on: | ||
9 | * iPAQ h2200 PCMCIA support | ||
10 | * Copyright 2004 Koen Kooi <koen@vestingbar.nl> | ||
11 | * | ||
12 | * This file is subject to the terms and conditions of the GNU General Public | ||
13 | * License. See the file COPYING in the main directory of this archive for | ||
14 | * more details. | ||
15 | */ | ||
16 | |||
17 | #include <linux/module.h> | ||
18 | #include <linux/init.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/platform_device.h> | ||
23 | #include <linux/gpio.h> | ||
24 | |||
25 | #include <pcmcia/ss.h> | ||
26 | |||
27 | #include <asm/irq.h> | ||
28 | |||
29 | #include <mach/pxa-regs.h> | ||
30 | #include <mach/viper.h> | ||
31 | #include <asm/mach-types.h> | ||
32 | |||
33 | #include "soc_common.h" | ||
34 | #include "pxa2xx_base.h" | ||
35 | |||
36 | static struct pcmcia_irqs irqs[] = { | ||
37 | { 0, gpio_to_irq(VIPER_CF_CD_GPIO), "PCMCIA_CD" } | ||
38 | }; | ||
39 | |||
40 | static int viper_pcmcia_hw_init(struct soc_pcmcia_socket *skt) | ||
41 | { | ||
42 | unsigned long flags; | ||
43 | |||
44 | skt->irq = gpio_to_irq(VIPER_CF_RDY_GPIO); | ||
45 | |||
46 | if (gpio_request(VIPER_CF_CD_GPIO, "CF detect")) | ||
47 | goto err_request_cd; | ||
48 | |||
49 | if (gpio_request(VIPER_CF_RDY_GPIO, "CF ready")) | ||
50 | goto err_request_rdy; | ||
51 | |||
52 | if (gpio_request(VIPER_CF_POWER_GPIO, "CF power")) | ||
53 | goto err_request_pwr; | ||
54 | |||
55 | local_irq_save(flags); | ||
56 | |||
57 | /* GPIO 82 is the CF power enable line. initially off */ | ||
58 | if (gpio_direction_output(VIPER_CF_POWER_GPIO, 0) || | ||
59 | gpio_direction_input(VIPER_CF_CD_GPIO) || | ||
60 | gpio_direction_input(VIPER_CF_RDY_GPIO)) { | ||
61 | local_irq_restore(flags); | ||
62 | goto err_dir; | ||
63 | } | ||
64 | |||
65 | local_irq_restore(flags); | ||
66 | |||
67 | return soc_pcmcia_request_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
68 | |||
69 | err_dir: | ||
70 | gpio_free(VIPER_CF_POWER_GPIO); | ||
71 | err_request_pwr: | ||
72 | gpio_free(VIPER_CF_RDY_GPIO); | ||
73 | err_request_rdy: | ||
74 | gpio_free(VIPER_CF_CD_GPIO); | ||
75 | err_request_cd: | ||
76 | printk(KERN_ERR "viper: Failed to setup PCMCIA GPIOs\n"); | ||
77 | return -1; | ||
78 | } | ||
79 | |||
80 | /* | ||
81 | * Release all resources. | ||
82 | */ | ||
83 | static void viper_pcmcia_hw_shutdown(struct soc_pcmcia_socket *skt) | ||
84 | { | ||
85 | soc_pcmcia_free_irqs(skt, irqs, ARRAY_SIZE(irqs)); | ||
86 | gpio_free(VIPER_CF_POWER_GPIO); | ||
87 | gpio_free(VIPER_CF_RDY_GPIO); | ||
88 | gpio_free(VIPER_CF_CD_GPIO); | ||
89 | } | ||
90 | |||
91 | static void viper_pcmcia_socket_state(struct soc_pcmcia_socket *skt, | ||
92 | struct pcmcia_state *state) | ||
93 | { | ||
94 | state->detect = gpio_get_value(VIPER_CF_CD_GPIO) ? 0 : 1; | ||
95 | state->ready = gpio_get_value(VIPER_CF_RDY_GPIO) ? 1 : 0; | ||
96 | state->bvd1 = 1; | ||
97 | state->bvd2 = 1; | ||
98 | state->wrprot = 0; | ||
99 | state->vs_3v = 1; /* Can only apply 3.3V */ | ||
100 | state->vs_Xv = 0; | ||
101 | } | ||
102 | |||
103 | static int viper_pcmcia_configure_socket(struct soc_pcmcia_socket *skt, | ||
104 | const socket_state_t *state) | ||
105 | { | ||
106 | /* Silently ignore Vpp, output enable, speaker enable. */ | ||
107 | viper_cf_rst(state->flags & SS_RESET); | ||
108 | |||
109 | /* Apply socket voltage */ | ||
110 | switch (state->Vcc) { | ||
111 | case 0: | ||
112 | gpio_set_value(VIPER_CF_POWER_GPIO, 0); | ||
113 | break; | ||
114 | case 33: | ||
115 | gpio_set_value(VIPER_CF_POWER_GPIO, 1); | ||
116 | break; | ||
117 | default: | ||
118 | printk(KERN_ERR "%s: Unsupported Vcc:%d\n", | ||
119 | __func__, state->Vcc); | ||
120 | return -1; | ||
121 | } | ||
122 | |||
123 | return 0; | ||
124 | } | ||
125 | |||
126 | static void viper_pcmcia_socket_init(struct soc_pcmcia_socket *skt) | ||
127 | { | ||
128 | } | ||
129 | |||
130 | static void viper_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt) | ||
131 | { | ||
132 | } | ||
133 | |||
134 | static struct pcmcia_low_level viper_pcmcia_ops __initdata = { | ||
135 | .owner = THIS_MODULE, | ||
136 | .hw_init = viper_pcmcia_hw_init, | ||
137 | .hw_shutdown = viper_pcmcia_hw_shutdown, | ||
138 | .socket_state = viper_pcmcia_socket_state, | ||
139 | .configure_socket = viper_pcmcia_configure_socket, | ||
140 | .socket_init = viper_pcmcia_socket_init, | ||
141 | .socket_suspend = viper_pcmcia_socket_suspend, | ||
142 | .nr = 1, | ||
143 | }; | ||
144 | |||
145 | static struct platform_device *viper_pcmcia_device; | ||
146 | |||
147 | static int __init viper_pcmcia_init(void) | ||
148 | { | ||
149 | int ret; | ||
150 | |||
151 | if (!machine_is_viper()) | ||
152 | return -ENODEV; | ||
153 | |||
154 | viper_pcmcia_device = platform_device_alloc("pxa2xx-pcmcia", -1); | ||
155 | if (!viper_pcmcia_device) | ||
156 | return -ENOMEM; | ||
157 | |||
158 | ret = platform_device_add_data(viper_pcmcia_device, | ||
159 | &viper_pcmcia_ops, | ||
160 | sizeof(viper_pcmcia_ops)); | ||
161 | |||
162 | if (!ret) | ||
163 | ret = platform_device_add(viper_pcmcia_device); | ||
164 | |||
165 | if (ret) | ||
166 | platform_device_put(viper_pcmcia_device); | ||
167 | |||
168 | return ret; | ||
169 | } | ||
170 | |||
171 | static void __exit viper_pcmcia_exit(void) | ||
172 | { | ||
173 | platform_device_unregister(viper_pcmcia_device); | ||
174 | } | ||
175 | |||
176 | module_init(viper_pcmcia_init); | ||
177 | module_exit(viper_pcmcia_exit); | ||
178 | |||
179 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 9ce55850271a..1982f8b42782 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig | |||
@@ -56,10 +56,10 @@ config BATTERY_TOSA | |||
56 | Say Y to enable support for the battery on the Sharp Zaurus | 56 | Say Y to enable support for the battery on the Sharp Zaurus |
57 | SL-6000 (tosa) models. | 57 | SL-6000 (tosa) models. |
58 | 58 | ||
59 | config BATTERY_PALMTX | 59 | config BATTERY_WM97XX |
60 | tristate "Palm T|X battery" | 60 | bool "WM97xx generic battery driver" |
61 | depends on MACH_PALMTX | 61 | depends on TOUCHSCREEN_WM97XX |
62 | help | 62 | help |
63 | Say Y to enable support for the battery in Palm T|X. | 63 | Say Y to enable support for battery measured by WM97xx aux port. |
64 | 64 | ||
65 | endif # POWER_SUPPLY | 65 | endif # POWER_SUPPLY |
diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 4706bf8ff459..4e20026cc45a 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile | |||
@@ -21,4 +21,4 @@ obj-$(CONFIG_BATTERY_DS2760) += ds2760_battery.o | |||
21 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o | 21 | obj-$(CONFIG_BATTERY_PMU) += pmu_battery.o |
22 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o | 22 | obj-$(CONFIG_BATTERY_OLPC) += olpc_battery.o |
23 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o | 23 | obj-$(CONFIG_BATTERY_TOSA) += tosa_battery.o |
24 | obj-$(CONFIG_BATTERY_PALMTX) += palmtx_battery.o | 24 | obj-$(CONFIG_BATTERY_WM97XX) += wm97xx_battery.o \ No newline at end of file |
diff --git a/drivers/power/palmtx_battery.c b/drivers/power/palmtx_battery.c deleted file mode 100644 index 7035bfa41c62..000000000000 --- a/drivers/power/palmtx_battery.c +++ /dev/null | |||
@@ -1,198 +0,0 @@ | |||
1 | /* | ||
2 | * linux/drivers/power/palmtx_battery.c | ||
3 | * | ||
4 | * Battery measurement code for Palm T|X Handheld computer | ||
5 | * | ||
6 | * based on tosa_battery.c | ||
7 | * | ||
8 | * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/power_supply.h> | ||
18 | #include <linux/wm97xx.h> | ||
19 | #include <linux/delay.h> | ||
20 | #include <linux/spinlock.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/gpio.h> | ||
23 | |||
24 | #include <asm/mach-types.h> | ||
25 | #include <mach/palmtx.h> | ||
26 | |||
27 | static DEFINE_MUTEX(bat_lock); | ||
28 | static struct work_struct bat_work; | ||
29 | struct mutex work_lock; | ||
30 | int bat_status = POWER_SUPPLY_STATUS_DISCHARGING; | ||
31 | |||
32 | static unsigned long palmtx_read_bat(struct power_supply *bat_ps) | ||
33 | { | ||
34 | return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data, | ||
35 | WM97XX_AUX_ID3) * 1000 / 414; | ||
36 | } | ||
37 | |||
38 | static unsigned long palmtx_read_temp(struct power_supply *bat_ps) | ||
39 | { | ||
40 | return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data, | ||
41 | WM97XX_AUX_ID2); | ||
42 | } | ||
43 | |||
44 | static int palmtx_bat_get_property(struct power_supply *bat_ps, | ||
45 | enum power_supply_property psp, | ||
46 | union power_supply_propval *val) | ||
47 | { | ||
48 | switch (psp) { | ||
49 | case POWER_SUPPLY_PROP_STATUS: | ||
50 | val->intval = bat_status; | ||
51 | break; | ||
52 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
53 | val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; | ||
54 | break; | ||
55 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
56 | val->intval = palmtx_read_bat(bat_ps); | ||
57 | break; | ||
58 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | ||
59 | case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN: | ||
60 | val->intval = PALMTX_BAT_MAX_VOLTAGE; | ||
61 | break; | ||
62 | case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN: | ||
63 | val->intval = PALMTX_BAT_MIN_VOLTAGE; | ||
64 | break; | ||
65 | case POWER_SUPPLY_PROP_TEMP: | ||
66 | val->intval = palmtx_read_temp(bat_ps); | ||
67 | break; | ||
68 | case POWER_SUPPLY_PROP_PRESENT: | ||
69 | val->intval = 1; | ||
70 | break; | ||
71 | default: | ||
72 | return -EINVAL; | ||
73 | } | ||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | static void palmtx_bat_external_power_changed(struct power_supply *bat_ps) | ||
78 | { | ||
79 | schedule_work(&bat_work); | ||
80 | } | ||
81 | |||
82 | static char *status_text[] = { | ||
83 | [POWER_SUPPLY_STATUS_UNKNOWN] = "Unknown", | ||
84 | [POWER_SUPPLY_STATUS_CHARGING] = "Charging", | ||
85 | [POWER_SUPPLY_STATUS_DISCHARGING] = "Discharging", | ||
86 | }; | ||
87 | |||
88 | static void palmtx_bat_update(struct power_supply *bat_ps) | ||
89 | { | ||
90 | int old_status = bat_status; | ||
91 | |||
92 | mutex_lock(&work_lock); | ||
93 | |||
94 | bat_status = gpio_get_value(GPIO_NR_PALMTX_POWER_DETECT) ? | ||
95 | POWER_SUPPLY_STATUS_CHARGING : | ||
96 | POWER_SUPPLY_STATUS_DISCHARGING; | ||
97 | |||
98 | if (old_status != bat_status) { | ||
99 | pr_debug("%s %s -> %s\n", bat_ps->name, | ||
100 | status_text[old_status], | ||
101 | status_text[bat_status]); | ||
102 | power_supply_changed(bat_ps); | ||
103 | } | ||
104 | |||
105 | mutex_unlock(&work_lock); | ||
106 | } | ||
107 | |||
108 | static enum power_supply_property palmtx_bat_main_props[] = { | ||
109 | POWER_SUPPLY_PROP_STATUS, | ||
110 | POWER_SUPPLY_PROP_TECHNOLOGY, | ||
111 | POWER_SUPPLY_PROP_VOLTAGE_NOW, | ||
112 | POWER_SUPPLY_PROP_VOLTAGE_MAX, | ||
113 | POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN, | ||
114 | POWER_SUPPLY_PROP_TEMP, | ||
115 | POWER_SUPPLY_PROP_PRESENT, | ||
116 | }; | ||
117 | |||
118 | struct power_supply bat_ps = { | ||
119 | .name = "main-battery", | ||
120 | .type = POWER_SUPPLY_TYPE_BATTERY, | ||
121 | .properties = palmtx_bat_main_props, | ||
122 | .num_properties = ARRAY_SIZE(palmtx_bat_main_props), | ||
123 | .get_property = palmtx_bat_get_property, | ||
124 | .external_power_changed = palmtx_bat_external_power_changed, | ||
125 | .use_for_apm = 1, | ||
126 | }; | ||
127 | |||
128 | static void palmtx_bat_work(struct work_struct *work) | ||
129 | { | ||
130 | palmtx_bat_update(&bat_ps); | ||
131 | } | ||
132 | |||
133 | #ifdef CONFIG_PM | ||
134 | static int palmtx_bat_suspend(struct platform_device *dev, pm_message_t state) | ||
135 | { | ||
136 | flush_scheduled_work(); | ||
137 | return 0; | ||
138 | } | ||
139 | |||
140 | static int palmtx_bat_resume(struct platform_device *dev) | ||
141 | { | ||
142 | schedule_work(&bat_work); | ||
143 | return 0; | ||
144 | } | ||
145 | #else | ||
146 | #define palmtx_bat_suspend NULL | ||
147 | #define palmtx_bat_resume NULL | ||
148 | #endif | ||
149 | |||
150 | static int __devinit palmtx_bat_probe(struct platform_device *dev) | ||
151 | { | ||
152 | int ret = 0; | ||
153 | |||
154 | if (!machine_is_palmtx()) | ||
155 | return -ENODEV; | ||
156 | |||
157 | mutex_init(&work_lock); | ||
158 | |||
159 | INIT_WORK(&bat_work, palmtx_bat_work); | ||
160 | |||
161 | ret = power_supply_register(&dev->dev, &bat_ps); | ||
162 | if (!ret) | ||
163 | schedule_work(&bat_work); | ||
164 | |||
165 | return ret; | ||
166 | } | ||
167 | |||
168 | static int __devexit palmtx_bat_remove(struct platform_device *dev) | ||
169 | { | ||
170 | power_supply_unregister(&bat_ps); | ||
171 | return 0; | ||
172 | } | ||
173 | |||
174 | static struct platform_driver palmtx_bat_driver = { | ||
175 | .driver.name = "wm97xx-battery", | ||
176 | .driver.owner = THIS_MODULE, | ||
177 | .probe = palmtx_bat_probe, | ||
178 | .remove = __devexit_p(palmtx_bat_remove), | ||
179 | .suspend = palmtx_bat_suspend, | ||
180 | .resume = palmtx_bat_resume, | ||
181 | }; | ||
182 | |||
183 | static int __init palmtx_bat_init(void) | ||
184 | { | ||
185 | return platform_driver_register(&palmtx_bat_driver); | ||
186 | } | ||
187 | |||
188 | static void __exit palmtx_bat_exit(void) | ||
189 | { | ||
190 | platform_driver_unregister(&palmtx_bat_driver); | ||
191 | } | ||
192 | |||
193 | module_init(palmtx_bat_init); | ||
194 | module_exit(palmtx_bat_exit); | ||
195 | |||
196 | MODULE_LICENSE("GPL"); | ||
197 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | ||
198 | MODULE_DESCRIPTION("Palm T|X battery driver"); | ||
diff --git a/drivers/power/wm97xx_battery.c b/drivers/power/wm97xx_battery.c new file mode 100644 index 000000000000..8bde92126d34 --- /dev/null +++ b/drivers/power/wm97xx_battery.c | |||
@@ -0,0 +1,272 @@ | |||
1 | /* | ||
2 | * linux/drivers/power/wm97xx_battery.c | ||
3 | * | ||
4 | * Battery measurement code for WM97xx | ||
5 | * | ||
6 | * based on tosa_battery.c | ||
7 | * | ||
8 | * Copyright (C) 2008 Marek Vasut <marek.vasut@gmail.com> | ||
9 | * | ||
10 | * This program is free software; you can redistribute it and/or modify | ||
11 | * it under the terms of the GNU General Public License version 2 as | ||
12 | * published by the Free Software Foundation. | ||
13 | * | ||
14 | */ | ||
15 | |||
16 | #include <linux/init.h> | ||
17 | #include <linux/kernel.h> | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/power_supply.h> | ||
21 | #include <linux/wm97xx.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/interrupt.h> | ||
24 | #include <linux/gpio.h> | ||
25 | #include <linux/wm97xx_batt.h> | ||
26 | |||
27 | static DEFINE_MUTEX(bat_lock); | ||
28 | static struct work_struct bat_work; | ||
29 | struct mutex work_lock; | ||
30 | static int bat_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
31 | static struct wm97xx_batt_info *pdata; | ||
32 | static enum power_supply_property *prop; | ||
33 | |||
34 | static unsigned long wm97xx_read_bat(struct power_supply *bat_ps) | ||
35 | { | ||
36 | return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data, | ||
37 | pdata->batt_aux) * pdata->batt_mult / | ||
38 | pdata->batt_div; | ||
39 | } | ||
40 | |||
41 | static unsigned long wm97xx_read_temp(struct power_supply *bat_ps) | ||
42 | { | ||
43 | return wm97xx_read_aux_adc(bat_ps->dev->parent->driver_data, | ||
44 | pdata->temp_aux) * pdata->temp_mult / | ||
45 | pdata->temp_div; | ||
46 | } | ||
47 | |||
48 | static int wm97xx_bat_get_property(struct power_supply *bat_ps, | ||
49 | enum power_supply_property psp, | ||
50 | union power_supply_propval *val) | ||
51 | { | ||
52 | switch (psp) { | ||
53 | case POWER_SUPPLY_PROP_STATUS: | ||
54 | val->intval = bat_status; | ||
55 | break; | ||
56 | case POWER_SUPPLY_PROP_TECHNOLOGY: | ||
57 | val->intval = pdata->batt_tech; | ||
58 | break; | ||
59 | case POWER_SUPPLY_PROP_VOLTAGE_NOW: | ||
60 | if (pdata->batt_aux >= 0) | ||
61 | val->intval = wm97xx_read_bat(bat_ps); | ||
62 | else | ||
63 | return -EINVAL; | ||
64 | break; | ||
65 | case POWER_SUPPLY_PROP_TEMP: | ||
66 | if (pdata->temp_aux >= 0) | ||
67 | val->intval = wm97xx_read_temp(bat_ps); | ||
68 | else | ||
69 | return -EINVAL; | ||
70 | break; | ||
71 | case POWER_SUPPLY_PROP_VOLTAGE_MAX: | ||
72 | if (pdata->max_voltage >= 0) | ||
73 | val->intval = pdata->max_voltage; | ||
74 | else | ||
75 | return -EINVAL; | ||
76 | break; | ||
77 | case POWER_SUPPLY_PROP_VOLTAGE_MIN: | ||
78 | if (pdata->min_voltage >= 0) | ||
79 | val->intval = pdata->min_voltage; | ||
80 | else | ||
81 | return -EINVAL; | ||
82 | break; | ||
83 | case POWER_SUPPLY_PROP_PRESENT: | ||
84 | val->intval = 1; | ||
85 | break; | ||
86 | default: | ||
87 | return -EINVAL; | ||
88 | } | ||
89 | return 0; | ||
90 | } | ||
91 | |||
92 | static void wm97xx_bat_external_power_changed(struct power_supply *bat_ps) | ||
93 | { | ||
94 | schedule_work(&bat_work); | ||
95 | } | ||
96 | |||
97 | static void wm97xx_bat_update(struct power_supply *bat_ps) | ||
98 | { | ||
99 | int old_status = bat_status; | ||
100 | |||
101 | mutex_lock(&work_lock); | ||
102 | |||
103 | bat_status = (pdata->charge_gpio >= 0) ? | ||
104 | (gpio_get_value(pdata->charge_gpio) ? | ||
105 | POWER_SUPPLY_STATUS_DISCHARGING : | ||
106 | POWER_SUPPLY_STATUS_CHARGING) : | ||
107 | POWER_SUPPLY_STATUS_UNKNOWN; | ||
108 | |||
109 | if (old_status != bat_status) { | ||
110 | pr_debug("%s: %i -> %i\n", bat_ps->name, old_status, | ||
111 | bat_status); | ||
112 | power_supply_changed(bat_ps); | ||
113 | } | ||
114 | |||
115 | mutex_unlock(&work_lock); | ||
116 | } | ||
117 | |||
118 | static struct power_supply bat_ps = { | ||
119 | .type = POWER_SUPPLY_TYPE_BATTERY, | ||
120 | .get_property = wm97xx_bat_get_property, | ||
121 | .external_power_changed = wm97xx_bat_external_power_changed, | ||
122 | .use_for_apm = 1, | ||
123 | }; | ||
124 | |||
125 | static void wm97xx_bat_work(struct work_struct *work) | ||
126 | { | ||
127 | wm97xx_bat_update(&bat_ps); | ||
128 | } | ||
129 | |||
130 | #ifdef CONFIG_PM | ||
131 | static int wm97xx_bat_suspend(struct platform_device *dev, pm_message_t state) | ||
132 | { | ||
133 | flush_scheduled_work(); | ||
134 | return 0; | ||
135 | } | ||
136 | |||
137 | static int wm97xx_bat_resume(struct platform_device *dev) | ||
138 | { | ||
139 | schedule_work(&bat_work); | ||
140 | return 0; | ||
141 | } | ||
142 | #else | ||
143 | #define wm97xx_bat_suspend NULL | ||
144 | #define wm97xx_bat_resume NULL | ||
145 | #endif | ||
146 | |||
147 | static int __devinit wm97xx_bat_probe(struct platform_device *dev) | ||
148 | { | ||
149 | int ret = 0; | ||
150 | int props = 1; /* POWER_SUPPLY_PROP_PRESENT */ | ||
151 | int i = 0; | ||
152 | |||
153 | if (dev->id != -1) | ||
154 | return -EINVAL; | ||
155 | |||
156 | mutex_init(&work_lock); | ||
157 | |||
158 | if (!pdata) { | ||
159 | dev_err(&dev->dev, "Please use wm97xx_bat_set_pdata\n"); | ||
160 | return -EINVAL; | ||
161 | } | ||
162 | |||
163 | if (pdata->charge_gpio >= 0 && gpio_is_valid(pdata->charge_gpio)) { | ||
164 | ret = gpio_request(pdata->charge_gpio, "BATT CHRG"); | ||
165 | if (ret) | ||
166 | goto err; | ||
167 | ret = gpio_direction_input(pdata->charge_gpio); | ||
168 | if (ret) | ||
169 | goto err2; | ||
170 | props++; /* POWER_SUPPLY_PROP_STATUS */ | ||
171 | } | ||
172 | |||
173 | if (pdata->batt_tech >= 0) | ||
174 | props++; /* POWER_SUPPLY_PROP_TECHNOLOGY */ | ||
175 | if (pdata->temp_aux >= 0) | ||
176 | props++; /* POWER_SUPPLY_PROP_TEMP */ | ||
177 | if (pdata->batt_aux >= 0) | ||
178 | props++; /* POWER_SUPPLY_PROP_VOLTAGE_NOW */ | ||
179 | if (pdata->max_voltage >= 0) | ||
180 | props++; /* POWER_SUPPLY_PROP_VOLTAGE_MAX */ | ||
181 | if (pdata->min_voltage >= 0) | ||
182 | props++; /* POWER_SUPPLY_PROP_VOLTAGE_MIN */ | ||
183 | |||
184 | prop = kzalloc(props * sizeof(*prop), GFP_KERNEL); | ||
185 | if (!prop) | ||
186 | goto err2; | ||
187 | |||
188 | prop[i++] = POWER_SUPPLY_PROP_PRESENT; | ||
189 | if (pdata->charge_gpio >= 0) | ||
190 | prop[i++] = POWER_SUPPLY_PROP_STATUS; | ||
191 | if (pdata->batt_tech >= 0) | ||
192 | prop[i++] = POWER_SUPPLY_PROP_TECHNOLOGY; | ||
193 | if (pdata->temp_aux >= 0) | ||
194 | prop[i++] = POWER_SUPPLY_PROP_TEMP; | ||
195 | if (pdata->batt_aux >= 0) | ||
196 | prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_NOW; | ||
197 | if (pdata->max_voltage >= 0) | ||
198 | prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MAX; | ||
199 | if (pdata->min_voltage >= 0) | ||
200 | prop[i++] = POWER_SUPPLY_PROP_VOLTAGE_MIN; | ||
201 | |||
202 | INIT_WORK(&bat_work, wm97xx_bat_work); | ||
203 | |||
204 | if (!pdata->batt_name) { | ||
205 | dev_info(&dev->dev, "Please consider setting proper battery " | ||
206 | "name in platform definition file, falling " | ||
207 | "back to name \"wm97xx-batt\"\n"); | ||
208 | bat_ps.name = "wm97xx-batt"; | ||
209 | } else | ||
210 | bat_ps.name = pdata->batt_name; | ||
211 | |||
212 | bat_ps.properties = prop; | ||
213 | bat_ps.num_properties = props; | ||
214 | |||
215 | ret = power_supply_register(&dev->dev, &bat_ps); | ||
216 | if (!ret) | ||
217 | schedule_work(&bat_work); | ||
218 | else | ||
219 | goto err3; | ||
220 | |||
221 | return 0; | ||
222 | err3: | ||
223 | kfree(prop); | ||
224 | err2: | ||
225 | gpio_free(pdata->charge_gpio); | ||
226 | err: | ||
227 | return ret; | ||
228 | } | ||
229 | |||
230 | static int __devexit wm97xx_bat_remove(struct platform_device *dev) | ||
231 | { | ||
232 | if (pdata && pdata->charge_gpio && pdata->charge_gpio >= 0) | ||
233 | gpio_free(pdata->charge_gpio); | ||
234 | flush_scheduled_work(); | ||
235 | power_supply_unregister(&bat_ps); | ||
236 | kfree(prop); | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static struct platform_driver wm97xx_bat_driver = { | ||
241 | .driver = { | ||
242 | .name = "wm97xx-battery", | ||
243 | .owner = THIS_MODULE, | ||
244 | }, | ||
245 | .probe = wm97xx_bat_probe, | ||
246 | .remove = __devexit_p(wm97xx_bat_remove), | ||
247 | .suspend = wm97xx_bat_suspend, | ||
248 | .resume = wm97xx_bat_resume, | ||
249 | }; | ||
250 | |||
251 | static int __init wm97xx_bat_init(void) | ||
252 | { | ||
253 | return platform_driver_register(&wm97xx_bat_driver); | ||
254 | } | ||
255 | |||
256 | static void __exit wm97xx_bat_exit(void) | ||
257 | { | ||
258 | platform_driver_unregister(&wm97xx_bat_driver); | ||
259 | } | ||
260 | |||
261 | void __init wm97xx_bat_set_pdata(struct wm97xx_batt_info *data) | ||
262 | { | ||
263 | pdata = data; | ||
264 | } | ||
265 | EXPORT_SYMBOL_GPL(wm97xx_bat_set_pdata); | ||
266 | |||
267 | module_init(wm97xx_bat_init); | ||
268 | module_exit(wm97xx_bat_exit); | ||
269 | |||
270 | MODULE_LICENSE("GPL"); | ||
271 | MODULE_AUTHOR("Marek Vasut <marek.vasut@gmail.com>"); | ||
272 | MODULE_DESCRIPTION("WM97xx battery driver"); | ||
diff --git a/drivers/serial/pxa.c b/drivers/serial/pxa.c index f7a0d37c4221..abc00be55433 100644 --- a/drivers/serial/pxa.c +++ b/drivers/serial/pxa.c | |||
@@ -534,6 +534,11 @@ serial_pxa_set_termios(struct uart_port *port, struct ktermios *termios, | |||
534 | 534 | ||
535 | serial_out(up, UART_IER, up->ier); | 535 | serial_out(up, UART_IER, up->ier); |
536 | 536 | ||
537 | if (termios->c_cflag & CRTSCTS) | ||
538 | up->mcr |= UART_MCR_AFE; | ||
539 | else | ||
540 | up->mcr &= ~UART_MCR_AFE; | ||
541 | |||
537 | serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ | 542 | serial_out(up, UART_LCR, cval | UART_LCR_DLAB);/* set DLAB */ |
538 | serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ | 543 | serial_out(up, UART_DLL, quot & 0xff); /* LS of divisor */ |
539 | serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ | 544 | serial_out(up, UART_DLM, quot >> 8); /* MS of divisor */ |
diff --git a/drivers/usb/host/ohci-pxa27x.c b/drivers/usb/host/ohci-pxa27x.c index 7f0f35c78185..e294d430733b 100644 --- a/drivers/usb/host/ohci-pxa27x.c +++ b/drivers/usb/host/ohci-pxa27x.c | |||
@@ -23,17 +23,90 @@ | |||
23 | #include <linux/signal.h> | 23 | #include <linux/signal.h> |
24 | #include <linux/platform_device.h> | 24 | #include <linux/platform_device.h> |
25 | #include <linux/clk.h> | 25 | #include <linux/clk.h> |
26 | |||
27 | #include <mach/hardware.h> | ||
28 | #include <mach/pxa-regs.h> | ||
29 | #include <mach/pxa2xx-regs.h> /* FIXME: for PSSR */ | ||
30 | #include <mach/ohci.h> | 26 | #include <mach/ohci.h> |
31 | 27 | ||
28 | /* | ||
29 | * UHC: USB Host Controller (OHCI-like) register definitions | ||
30 | */ | ||
31 | #define UHCREV (0x0000) /* UHC HCI Spec Revision */ | ||
32 | #define UHCHCON (0x0004) /* UHC Host Control Register */ | ||
33 | #define UHCCOMS (0x0008) /* UHC Command Status Register */ | ||
34 | #define UHCINTS (0x000C) /* UHC Interrupt Status Register */ | ||
35 | #define UHCINTE (0x0010) /* UHC Interrupt Enable */ | ||
36 | #define UHCINTD (0x0014) /* UHC Interrupt Disable */ | ||
37 | #define UHCHCCA (0x0018) /* UHC Host Controller Comm. Area */ | ||
38 | #define UHCPCED (0x001C) /* UHC Period Current Endpt Descr */ | ||
39 | #define UHCCHED (0x0020) /* UHC Control Head Endpt Descr */ | ||
40 | #define UHCCCED (0x0024) /* UHC Control Current Endpt Descr */ | ||
41 | #define UHCBHED (0x0028) /* UHC Bulk Head Endpt Descr */ | ||
42 | #define UHCBCED (0x002C) /* UHC Bulk Current Endpt Descr */ | ||
43 | #define UHCDHEAD (0x0030) /* UHC Done Head */ | ||
44 | #define UHCFMI (0x0034) /* UHC Frame Interval */ | ||
45 | #define UHCFMR (0x0038) /* UHC Frame Remaining */ | ||
46 | #define UHCFMN (0x003C) /* UHC Frame Number */ | ||
47 | #define UHCPERS (0x0040) /* UHC Periodic Start */ | ||
48 | #define UHCLS (0x0044) /* UHC Low Speed Threshold */ | ||
49 | |||
50 | #define UHCRHDA (0x0048) /* UHC Root Hub Descriptor A */ | ||
51 | #define UHCRHDA_NOCP (1 << 12) /* No over current protection */ | ||
52 | #define UHCRHDA_OCPM (1 << 11) /* Over Current Protection Mode */ | ||
53 | #define UHCRHDA_POTPGT(x) \ | ||
54 | (((x) & 0xff) << 24) /* Power On To Power Good Time */ | ||
55 | |||
56 | #define UHCRHDB (0x004C) /* UHC Root Hub Descriptor B */ | ||
57 | #define UHCRHS (0x0050) /* UHC Root Hub Status */ | ||
58 | #define UHCRHPS1 (0x0054) /* UHC Root Hub Port 1 Status */ | ||
59 | #define UHCRHPS2 (0x0058) /* UHC Root Hub Port 2 Status */ | ||
60 | #define UHCRHPS3 (0x005C) /* UHC Root Hub Port 3 Status */ | ||
61 | |||
62 | #define UHCSTAT (0x0060) /* UHC Status Register */ | ||
63 | #define UHCSTAT_UPS3 (1 << 16) /* USB Power Sense Port3 */ | ||
64 | #define UHCSTAT_SBMAI (1 << 15) /* System Bus Master Abort Interrupt*/ | ||
65 | #define UHCSTAT_SBTAI (1 << 14) /* System Bus Target Abort Interrupt*/ | ||
66 | #define UHCSTAT_UPRI (1 << 13) /* USB Port Resume Interrupt */ | ||
67 | #define UHCSTAT_UPS2 (1 << 12) /* USB Power Sense Port 2 */ | ||
68 | #define UHCSTAT_UPS1 (1 << 11) /* USB Power Sense Port 1 */ | ||
69 | #define UHCSTAT_HTA (1 << 10) /* HCI Target Abort */ | ||
70 | #define UHCSTAT_HBA (1 << 8) /* HCI Buffer Active */ | ||
71 | #define UHCSTAT_RWUE (1 << 7) /* HCI Remote Wake Up Event */ | ||
72 | |||
73 | #define UHCHR (0x0064) /* UHC Reset Register */ | ||
74 | #define UHCHR_SSEP3 (1 << 11) /* Sleep Standby Enable for Port3 */ | ||
75 | #define UHCHR_SSEP2 (1 << 10) /* Sleep Standby Enable for Port2 */ | ||
76 | #define UHCHR_SSEP1 (1 << 9) /* Sleep Standby Enable for Port1 */ | ||
77 | #define UHCHR_PCPL (1 << 7) /* Power control polarity low */ | ||
78 | #define UHCHR_PSPL (1 << 6) /* Power sense polarity low */ | ||
79 | #define UHCHR_SSE (1 << 5) /* Sleep Standby Enable */ | ||
80 | #define UHCHR_UIT (1 << 4) /* USB Interrupt Test */ | ||
81 | #define UHCHR_SSDC (1 << 3) /* Simulation Scale Down Clock */ | ||
82 | #define UHCHR_CGR (1 << 2) /* Clock Generation Reset */ | ||
83 | #define UHCHR_FHR (1 << 1) /* Force Host Controller Reset */ | ||
84 | #define UHCHR_FSBIR (1 << 0) /* Force System Bus Iface Reset */ | ||
85 | |||
86 | #define UHCHIE (0x0068) /* UHC Interrupt Enable Register*/ | ||
87 | #define UHCHIE_UPS3IE (1 << 14) /* Power Sense Port3 IntEn */ | ||
88 | #define UHCHIE_UPRIE (1 << 13) /* Port Resume IntEn */ | ||
89 | #define UHCHIE_UPS2IE (1 << 12) /* Power Sense Port2 IntEn */ | ||
90 | #define UHCHIE_UPS1IE (1 << 11) /* Power Sense Port1 IntEn */ | ||
91 | #define UHCHIE_TAIE (1 << 10) /* HCI Interface Transfer Abort | ||
92 | Interrupt Enable*/ | ||
93 | #define UHCHIE_HBAIE (1 << 8) /* HCI Buffer Active IntEn */ | ||
94 | #define UHCHIE_RWIE (1 << 7) /* Remote Wake-up IntEn */ | ||
95 | |||
96 | #define UHCHIT (0x006C) /* UHC Interrupt Test register */ | ||
97 | |||
32 | #define PXA_UHC_MAX_PORTNUM 3 | 98 | #define PXA_UHC_MAX_PORTNUM 3 |
33 | 99 | ||
34 | #define UHCRHPS(x) __REG2( 0x4C000050, (x)<<2 ) | 100 | struct pxa27x_ohci { |
101 | /* must be 1st member here for hcd_to_ohci() to work */ | ||
102 | struct ohci_hcd ohci; | ||
103 | |||
104 | struct device *dev; | ||
105 | struct clk *clk; | ||
106 | void __iomem *mmio_base; | ||
107 | }; | ||
35 | 108 | ||
36 | static struct clk *usb_clk; | 109 | #define to_pxa27x_ohci(hcd) (struct pxa27x_ohci *)hcd_to_ohci(hcd) |
37 | 110 | ||
38 | /* | 111 | /* |
39 | PMM_NPS_MODE -- PMM Non-power switching mode | 112 | PMM_NPS_MODE -- PMM Non-power switching mode |
@@ -45,30 +118,35 @@ static struct clk *usb_clk; | |||
45 | PMM_PERPORT_MODE -- PMM per port switching mode | 118 | PMM_PERPORT_MODE -- PMM per port switching mode |
46 | Ports are powered individually. | 119 | Ports are powered individually. |
47 | */ | 120 | */ |
48 | static int pxa27x_ohci_select_pmm( int mode ) | 121 | static int pxa27x_ohci_select_pmm(struct pxa27x_ohci *ohci, int mode) |
49 | { | 122 | { |
50 | switch ( mode ) { | 123 | uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); |
124 | uint32_t uhcrhdb = __raw_readl(ohci->mmio_base + UHCRHDB); | ||
125 | |||
126 | switch (mode) { | ||
51 | case PMM_NPS_MODE: | 127 | case PMM_NPS_MODE: |
52 | UHCRHDA |= RH_A_NPS; | 128 | uhcrhda |= RH_A_NPS; |
53 | break; | 129 | break; |
54 | case PMM_GLOBAL_MODE: | 130 | case PMM_GLOBAL_MODE: |
55 | UHCRHDA &= ~(RH_A_NPS & RH_A_PSM); | 131 | uhcrhda &= ~(RH_A_NPS & RH_A_PSM); |
56 | break; | 132 | break; |
57 | case PMM_PERPORT_MODE: | 133 | case PMM_PERPORT_MODE: |
58 | UHCRHDA &= ~(RH_A_NPS); | 134 | uhcrhda &= ~(RH_A_NPS); |
59 | UHCRHDA |= RH_A_PSM; | 135 | uhcrhda |= RH_A_PSM; |
60 | 136 | ||
61 | /* Set port power control mask bits, only 3 ports. */ | 137 | /* Set port power control mask bits, only 3 ports. */ |
62 | UHCRHDB |= (0x7<<17); | 138 | uhcrhdb |= (0x7<<17); |
63 | break; | 139 | break; |
64 | default: | 140 | default: |
65 | printk( KERN_ERR | 141 | printk( KERN_ERR |
66 | "Invalid mode %d, set to non-power switch mode.\n", | 142 | "Invalid mode %d, set to non-power switch mode.\n", |
67 | mode ); | 143 | mode ); |
68 | 144 | ||
69 | UHCRHDA |= RH_A_NPS; | 145 | uhcrhda |= RH_A_NPS; |
70 | } | 146 | } |
71 | 147 | ||
148 | __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); | ||
149 | __raw_writel(uhcrhdb, ohci->mmio_base + UHCRHDB); | ||
72 | return 0; | 150 | return 0; |
73 | } | 151 | } |
74 | 152 | ||
@@ -76,57 +154,110 @@ extern int usb_disabled(void); | |||
76 | 154 | ||
77 | /*-------------------------------------------------------------------------*/ | 155 | /*-------------------------------------------------------------------------*/ |
78 | 156 | ||
79 | static int pxa27x_start_hc(struct device *dev) | 157 | static inline void pxa27x_setup_hc(struct pxa27x_ohci *ohci, |
158 | struct pxaohci_platform_data *inf) | ||
159 | { | ||
160 | uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); | ||
161 | uint32_t uhcrhda = __raw_readl(ohci->mmio_base + UHCRHDA); | ||
162 | |||
163 | if (inf->flags & ENABLE_PORT1) | ||
164 | uhchr &= ~UHCHR_SSEP1; | ||
165 | |||
166 | if (inf->flags & ENABLE_PORT2) | ||
167 | uhchr &= ~UHCHR_SSEP2; | ||
168 | |||
169 | if (inf->flags & ENABLE_PORT3) | ||
170 | uhchr &= ~UHCHR_SSEP3; | ||
171 | |||
172 | if (inf->flags & POWER_CONTROL_LOW) | ||
173 | uhchr |= UHCHR_PCPL; | ||
174 | |||
175 | if (inf->flags & POWER_SENSE_LOW) | ||
176 | uhchr |= UHCHR_PSPL; | ||
177 | |||
178 | if (inf->flags & NO_OC_PROTECTION) | ||
179 | uhcrhda |= UHCRHDA_NOCP; | ||
180 | |||
181 | if (inf->flags & OC_MODE_PERPORT) | ||
182 | uhcrhda |= UHCRHDA_OCPM; | ||
183 | |||
184 | if (inf->power_on_delay) { | ||
185 | uhcrhda &= ~UHCRHDA_POTPGT(0xff); | ||
186 | uhcrhda |= UHCRHDA_POTPGT(inf->power_on_delay / 2); | ||
187 | } | ||
188 | |||
189 | __raw_writel(uhchr, ohci->mmio_base + UHCHR); | ||
190 | __raw_writel(uhcrhda, ohci->mmio_base + UHCRHDA); | ||
191 | } | ||
192 | |||
193 | static inline void pxa27x_reset_hc(struct pxa27x_ohci *ohci) | ||
194 | { | ||
195 | uint32_t uhchr = __raw_readl(ohci->mmio_base + UHCHR); | ||
196 | |||
197 | __raw_writel(uhchr | UHCHR_FHR, ohci->mmio_base + UHCHR); | ||
198 | udelay(11); | ||
199 | __raw_writel(uhchr & ~UHCHR_FHR, ohci->mmio_base + UHCHR); | ||
200 | } | ||
201 | |||
202 | #ifdef CONFIG_CPU_PXA27x | ||
203 | extern void pxa27x_clear_otgph(void); | ||
204 | #else | ||
205 | #define pxa27x_clear_otgph() do {} while (0) | ||
206 | #endif | ||
207 | |||
208 | static int pxa27x_start_hc(struct pxa27x_ohci *ohci, struct device *dev) | ||
80 | { | 209 | { |
81 | int retval = 0; | 210 | int retval = 0; |
82 | struct pxaohci_platform_data *inf; | 211 | struct pxaohci_platform_data *inf; |
212 | uint32_t uhchr; | ||
83 | 213 | ||
84 | inf = dev->platform_data; | 214 | inf = dev->platform_data; |
85 | 215 | ||
86 | clk_enable(usb_clk); | 216 | clk_enable(ohci->clk); |
87 | 217 | ||
88 | UHCHR |= UHCHR_FHR; | 218 | pxa27x_reset_hc(ohci); |
89 | udelay(11); | 219 | |
90 | UHCHR &= ~UHCHR_FHR; | 220 | uhchr = __raw_readl(ohci->mmio_base + UHCHR) | UHCHR_FSBIR; |
221 | __raw_writel(uhchr, ohci->mmio_base + UHCHR); | ||
91 | 222 | ||
92 | UHCHR |= UHCHR_FSBIR; | 223 | while (__raw_readl(ohci->mmio_base + UHCHR) & UHCHR_FSBIR) |
93 | while (UHCHR & UHCHR_FSBIR) | ||
94 | cpu_relax(); | 224 | cpu_relax(); |
95 | 225 | ||
226 | pxa27x_setup_hc(ohci, inf); | ||
227 | |||
96 | if (inf->init) | 228 | if (inf->init) |
97 | retval = inf->init(dev); | 229 | retval = inf->init(dev); |
98 | 230 | ||
99 | if (retval < 0) | 231 | if (retval < 0) |
100 | return retval; | 232 | return retval; |
101 | 233 | ||
102 | UHCHR &= ~UHCHR_SSE; | 234 | uhchr = __raw_readl(ohci->mmio_base + UHCHR) & ~UHCHR_SSE; |
103 | 235 | __raw_writel(uhchr, ohci->mmio_base + UHCHR); | |
104 | UHCHIE = (UHCHIE_UPRIE | UHCHIE_RWIE); | 236 | __raw_writel(UHCHIE_UPRIE | UHCHIE_RWIE, ohci->mmio_base + UHCHIE); |
105 | 237 | ||
106 | /* Clear any OTG Pin Hold */ | 238 | /* Clear any OTG Pin Hold */ |
107 | if (cpu_is_pxa27x() && (PSSR & PSSR_OTGPH)) | 239 | pxa27x_clear_otgph(); |
108 | PSSR |= PSSR_OTGPH; | ||
109 | |||
110 | return 0; | 240 | return 0; |
111 | } | 241 | } |
112 | 242 | ||
113 | static void pxa27x_stop_hc(struct device *dev) | 243 | static void pxa27x_stop_hc(struct pxa27x_ohci *ohci, struct device *dev) |
114 | { | 244 | { |
115 | struct pxaohci_platform_data *inf; | 245 | struct pxaohci_platform_data *inf; |
246 | uint32_t uhccoms; | ||
116 | 247 | ||
117 | inf = dev->platform_data; | 248 | inf = dev->platform_data; |
118 | 249 | ||
119 | if (inf->exit) | 250 | if (inf->exit) |
120 | inf->exit(dev); | 251 | inf->exit(dev); |
121 | 252 | ||
122 | UHCHR |= UHCHR_FHR; | 253 | pxa27x_reset_hc(ohci); |
123 | udelay(11); | ||
124 | UHCHR &= ~UHCHR_FHR; | ||
125 | 254 | ||
126 | UHCCOMS |= 1; | 255 | /* Host Controller Reset */ |
256 | uhccoms = __raw_readl(ohci->mmio_base + UHCCOMS) | 0x01; | ||
257 | __raw_writel(uhccoms, ohci->mmio_base + UHCCOMS); | ||
127 | udelay(10); | 258 | udelay(10); |
128 | 259 | ||
129 | clk_disable(usb_clk); | 260 | clk_disable(ohci->clk); |
130 | } | 261 | } |
131 | 262 | ||
132 | 263 | ||
@@ -147,18 +278,22 @@ static void pxa27x_stop_hc(struct device *dev) | |||
147 | */ | 278 | */ |
148 | int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device *pdev) | 279 | int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device *pdev) |
149 | { | 280 | { |
150 | int retval; | 281 | int retval, irq; |
151 | struct usb_hcd *hcd; | 282 | struct usb_hcd *hcd; |
152 | struct pxaohci_platform_data *inf; | 283 | struct pxaohci_platform_data *inf; |
284 | struct pxa27x_ohci *ohci; | ||
285 | struct resource *r; | ||
286 | struct clk *usb_clk; | ||
153 | 287 | ||
154 | inf = pdev->dev.platform_data; | 288 | inf = pdev->dev.platform_data; |
155 | 289 | ||
156 | if (!inf) | 290 | if (!inf) |
157 | return -ENODEV; | 291 | return -ENODEV; |
158 | 292 | ||
159 | if (pdev->resource[1].flags != IORESOURCE_IRQ) { | 293 | irq = platform_get_irq(pdev, 0); |
160 | pr_debug ("resource[1] is not IORESOURCE_IRQ"); | 294 | if (irq < 0) { |
161 | return -ENOMEM; | 295 | pr_err("no resource of IORESOURCE_IRQ"); |
296 | return -ENXIO; | ||
162 | } | 297 | } |
163 | 298 | ||
164 | usb_clk = clk_get(&pdev->dev, "USBCLK"); | 299 | usb_clk = clk_get(&pdev->dev, "USBCLK"); |
@@ -168,8 +303,16 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device | |||
168 | hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x"); | 303 | hcd = usb_create_hcd (driver, &pdev->dev, "pxa27x"); |
169 | if (!hcd) | 304 | if (!hcd) |
170 | return -ENOMEM; | 305 | return -ENOMEM; |
171 | hcd->rsrc_start = pdev->resource[0].start; | 306 | |
172 | hcd->rsrc_len = pdev->resource[0].end - pdev->resource[0].start + 1; | 307 | r = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
308 | if (!r) { | ||
309 | pr_err("no resource of IORESOURCE_MEM"); | ||
310 | retval = -ENXIO; | ||
311 | goto err1; | ||
312 | } | ||
313 | |||
314 | hcd->rsrc_start = r->start; | ||
315 | hcd->rsrc_len = resource_size(r); | ||
173 | 316 | ||
174 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { | 317 | if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) { |
175 | pr_debug("request_mem_region failed"); | 318 | pr_debug("request_mem_region failed"); |
@@ -184,24 +327,30 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device | |||
184 | goto err2; | 327 | goto err2; |
185 | } | 328 | } |
186 | 329 | ||
187 | if ((retval = pxa27x_start_hc(&pdev->dev)) < 0) { | 330 | /* initialize "struct pxa27x_ohci" */ |
331 | ohci = (struct pxa27x_ohci *)hcd_to_ohci(hcd); | ||
332 | ohci->dev = &pdev->dev; | ||
333 | ohci->clk = usb_clk; | ||
334 | ohci->mmio_base = (void __iomem *)hcd->regs; | ||
335 | |||
336 | if ((retval = pxa27x_start_hc(ohci, &pdev->dev)) < 0) { | ||
188 | pr_debug("pxa27x_start_hc failed"); | 337 | pr_debug("pxa27x_start_hc failed"); |
189 | goto err3; | 338 | goto err3; |
190 | } | 339 | } |
191 | 340 | ||
192 | /* Select Power Management Mode */ | 341 | /* Select Power Management Mode */ |
193 | pxa27x_ohci_select_pmm(inf->port_mode); | 342 | pxa27x_ohci_select_pmm(ohci, inf->port_mode); |
194 | 343 | ||
195 | if (inf->power_budget) | 344 | if (inf->power_budget) |
196 | hcd->power_budget = inf->power_budget; | 345 | hcd->power_budget = inf->power_budget; |
197 | 346 | ||
198 | ohci_hcd_init(hcd_to_ohci(hcd)); | 347 | ohci_hcd_init(hcd_to_ohci(hcd)); |
199 | 348 | ||
200 | retval = usb_add_hcd(hcd, pdev->resource[1].start, IRQF_DISABLED); | 349 | retval = usb_add_hcd(hcd, irq, IRQF_DISABLED); |
201 | if (retval == 0) | 350 | if (retval == 0) |
202 | return retval; | 351 | return retval; |
203 | 352 | ||
204 | pxa27x_stop_hc(&pdev->dev); | 353 | pxa27x_stop_hc(ohci, &pdev->dev); |
205 | err3: | 354 | err3: |
206 | iounmap(hcd->regs); | 355 | iounmap(hcd->regs); |
207 | err2: | 356 | err2: |
@@ -228,12 +377,14 @@ int usb_hcd_pxa27x_probe (const struct hc_driver *driver, struct platform_device | |||
228 | */ | 377 | */ |
229 | void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev) | 378 | void usb_hcd_pxa27x_remove (struct usb_hcd *hcd, struct platform_device *pdev) |
230 | { | 379 | { |
380 | struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); | ||
381 | |||
231 | usb_remove_hcd(hcd); | 382 | usb_remove_hcd(hcd); |
232 | pxa27x_stop_hc(&pdev->dev); | 383 | pxa27x_stop_hc(ohci, &pdev->dev); |
233 | iounmap(hcd->regs); | 384 | iounmap(hcd->regs); |
234 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); | 385 | release_mem_region(hcd->rsrc_start, hcd->rsrc_len); |
235 | usb_put_hcd(hcd); | 386 | usb_put_hcd(hcd); |
236 | clk_put(usb_clk); | 387 | clk_put(ohci->clk); |
237 | } | 388 | } |
238 | 389 | ||
239 | /*-------------------------------------------------------------------------*/ | 390 | /*-------------------------------------------------------------------------*/ |
@@ -266,7 +417,7 @@ ohci_pxa27x_start (struct usb_hcd *hcd) | |||
266 | static const struct hc_driver ohci_pxa27x_hc_driver = { | 417 | static const struct hc_driver ohci_pxa27x_hc_driver = { |
267 | .description = hcd_name, | 418 | .description = hcd_name, |
268 | .product_desc = "PXA27x OHCI", | 419 | .product_desc = "PXA27x OHCI", |
269 | .hcd_priv_size = sizeof(struct ohci_hcd), | 420 | .hcd_priv_size = sizeof(struct pxa27x_ohci), |
270 | 421 | ||
271 | /* | 422 | /* |
272 | * generic hardware linkage | 423 | * generic hardware linkage |
@@ -330,13 +481,13 @@ static int ohci_hcd_pxa27x_drv_remove(struct platform_device *pdev) | |||
330 | static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_t state) | 481 | static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_t state) |
331 | { | 482 | { |
332 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | 483 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
333 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | 484 | struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); |
334 | 485 | ||
335 | if (time_before(jiffies, ohci->next_statechange)) | 486 | if (time_before(jiffies, ohci->ohci.next_statechange)) |
336 | msleep(5); | 487 | msleep(5); |
337 | ohci->next_statechange = jiffies; | 488 | ohci->ohci.next_statechange = jiffies; |
338 | 489 | ||
339 | pxa27x_stop_hc(&pdev->dev); | 490 | pxa27x_stop_hc(ohci, &pdev->dev); |
340 | hcd->state = HC_STATE_SUSPENDED; | 491 | hcd->state = HC_STATE_SUSPENDED; |
341 | 492 | ||
342 | return 0; | 493 | return 0; |
@@ -345,14 +496,14 @@ static int ohci_hcd_pxa27x_drv_suspend(struct platform_device *pdev, pm_message_ | |||
345 | static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev) | 496 | static int ohci_hcd_pxa27x_drv_resume(struct platform_device *pdev) |
346 | { | 497 | { |
347 | struct usb_hcd *hcd = platform_get_drvdata(pdev); | 498 | struct usb_hcd *hcd = platform_get_drvdata(pdev); |
348 | struct ohci_hcd *ohci = hcd_to_ohci(hcd); | 499 | struct pxa27x_ohci *ohci = to_pxa27x_ohci(hcd); |
349 | int status; | 500 | int status; |
350 | 501 | ||
351 | if (time_before(jiffies, ohci->next_statechange)) | 502 | if (time_before(jiffies, ohci->ohci.next_statechange)) |
352 | msleep(5); | 503 | msleep(5); |
353 | ohci->next_statechange = jiffies; | 504 | ohci->ohci.next_statechange = jiffies; |
354 | 505 | ||
355 | if ((status = pxa27x_start_hc(&pdev->dev)) < 0) | 506 | if ((status = pxa27x_start_hc(ohci, &pdev->dev)) < 0) |
356 | return status; | 507 | return status; |
357 | 508 | ||
358 | ohci_finish_controller_resume(hcd); | 509 | ohci_finish_controller_resume(hcd); |
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 70d135e0cc47..d85a74c64b54 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -172,11 +172,6 @@ config FB_DEFERRED_IO | |||
172 | bool | 172 | bool |
173 | depends on FB | 173 | depends on FB |
174 | 174 | ||
175 | config FB_METRONOME | ||
176 | tristate | ||
177 | depends on FB | ||
178 | depends on FB_DEFERRED_IO | ||
179 | |||
180 | config FB_HECUBA | 175 | config FB_HECUBA |
181 | tristate | 176 | tristate |
182 | depends on FB | 177 | depends on FB |
@@ -1974,19 +1969,6 @@ config FB_XILINX | |||
1974 | framebuffer. ML300 carries a 640*480 LCD display on the board, | 1969 | framebuffer. ML300 carries a 640*480 LCD display on the board, |
1975 | ML403 uses a standard DB15 VGA connector. | 1970 | ML403 uses a standard DB15 VGA connector. |
1976 | 1971 | ||
1977 | config FB_AM200EPD | ||
1978 | tristate "AM-200 E-Ink EPD devkit support" | ||
1979 | depends on FB && ARCH_PXA && MMU | ||
1980 | select FB_SYS_FILLRECT | ||
1981 | select FB_SYS_COPYAREA | ||
1982 | select FB_SYS_IMAGEBLIT | ||
1983 | select FB_SYS_FOPS | ||
1984 | select FB_DEFERRED_IO | ||
1985 | select FB_METRONOME | ||
1986 | help | ||
1987 | This enables support for the Metronome display controller used on | ||
1988 | the E-Ink AM-200 EPD devkit. | ||
1989 | |||
1990 | config FB_COBALT | 1972 | config FB_COBALT |
1991 | tristate "Cobalt server LCD frame buffer support" | 1973 | tristate "Cobalt server LCD frame buffer support" |
1992 | depends on FB && MIPS_COBALT | 1974 | depends on FB && MIPS_COBALT |
@@ -2041,6 +2023,19 @@ config XEN_FBDEV_FRONTEND | |||
2041 | frame buffer driver. It communicates with a back-end | 2023 | frame buffer driver. It communicates with a back-end |
2042 | in another domain. | 2024 | in another domain. |
2043 | 2025 | ||
2026 | config FB_METRONOME | ||
2027 | tristate "E-Ink Metronome/8track controller support" | ||
2028 | depends on FB | ||
2029 | select FB_SYS_FILLRECT | ||
2030 | select FB_SYS_COPYAREA | ||
2031 | select FB_SYS_IMAGEBLIT | ||
2032 | select FB_SYS_FOPS | ||
2033 | select FB_DEFERRED_IO | ||
2034 | help | ||
2035 | This driver implements support for the E-Ink Metronome | ||
2036 | controller. The pre-release name for this device was 8track | ||
2037 | and could also have been called by some vendors as PVI-nnnn. | ||
2038 | |||
2044 | source "drivers/video/omap/Kconfig" | 2039 | source "drivers/video/omap/Kconfig" |
2045 | 2040 | ||
2046 | source "drivers/video/backlight/Kconfig" | 2041 | source "drivers/video/backlight/Kconfig" |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index a6b55297a7fb..ad0330bf9be3 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -29,7 +29,6 @@ obj-$(CONFIG_FB_DEFERRED_IO) += fb_defio.o | |||
29 | 29 | ||
30 | # Hardware specific drivers go first | 30 | # Hardware specific drivers go first |
31 | obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o | 31 | obj-$(CONFIG_FB_AMIGA) += amifb.o c2p.o |
32 | obj-$(CONFIG_FB_AM200EPD) += am200epd.o | ||
33 | obj-$(CONFIG_FB_ARC) += arcfb.o | 32 | obj-$(CONFIG_FB_ARC) += arcfb.o |
34 | obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o | 33 | obj-$(CONFIG_FB_CLPS711X) += clps711xfb.o |
35 | obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o | 34 | obj-$(CONFIG_FB_CYBER2000) += cyber2000fb.o |
diff --git a/drivers/video/am200epd.c b/drivers/video/am200epd.c deleted file mode 100644 index 0c35b8b0160e..000000000000 --- a/drivers/video/am200epd.c +++ /dev/null | |||
@@ -1,295 +0,0 @@ | |||
1 | /* | ||
2 | * linux/drivers/video/am200epd.c -- Platform device for AM200 EPD kit | ||
3 | * | ||
4 | * Copyright (C) 2008, Jaya Kumar | ||
5 | * | ||
6 | * This file is subject to the terms and conditions of the GNU General Public | ||
7 | * License. See the file COPYING in the main directory of this archive for | ||
8 | * more details. | ||
9 | * | ||
10 | * Layout is based on skeletonfb.c by James Simmons and Geert Uytterhoeven. | ||
11 | * | ||
12 | * This work was made possible by help and equipment support from E-Ink | ||
13 | * Corporation. http://support.eink.com/community | ||
14 | * | ||
15 | * This driver is written to be used with the Metronome display controller. | ||
16 | * on the AM200 EPD prototype kit/development kit with an E-Ink 800x600 | ||
17 | * Vizplex EPD on a Gumstix board using the Lyre interface board. | ||
18 | * | ||
19 | */ | ||
20 | |||
21 | #include <linux/module.h> | ||
22 | #include <linux/kernel.h> | ||
23 | #include <linux/errno.h> | ||
24 | #include <linux/string.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include <linux/interrupt.h> | ||
27 | #include <linux/fb.h> | ||
28 | #include <linux/init.h> | ||
29 | #include <linux/platform_device.h> | ||
30 | #include <linux/list.h> | ||
31 | #include <linux/uaccess.h> | ||
32 | #include <linux/irq.h> | ||
33 | |||
34 | #include <video/metronomefb.h> | ||
35 | |||
36 | #include <mach/pxa-regs.h> | ||
37 | |||
38 | /* register offsets for gpio control */ | ||
39 | #define LED_GPIO_PIN 51 | ||
40 | #define STDBY_GPIO_PIN 48 | ||
41 | #define RST_GPIO_PIN 49 | ||
42 | #define RDY_GPIO_PIN 32 | ||
43 | #define ERR_GPIO_PIN 17 | ||
44 | #define PCBPWR_GPIO_PIN 16 | ||
45 | |||
46 | #define AF_SEL_GPIO_N 0x3 | ||
47 | #define GAFR0_U_OFFSET(pin) ((pin - 16) * 2) | ||
48 | #define GAFR1_L_OFFSET(pin) ((pin - 32) * 2) | ||
49 | #define GAFR1_U_OFFSET(pin) ((pin - 48) * 2) | ||
50 | #define GPDR1_OFFSET(pin) (pin - 32) | ||
51 | #define GPCR1_OFFSET(pin) (pin - 32) | ||
52 | #define GPSR1_OFFSET(pin) (pin - 32) | ||
53 | #define GPCR0_OFFSET(pin) (pin) | ||
54 | #define GPSR0_OFFSET(pin) (pin) | ||
55 | |||
56 | static void am200_set_gpio_output(int pin, int val) | ||
57 | { | ||
58 | u8 index; | ||
59 | |||
60 | index = pin >> 4; | ||
61 | |||
62 | switch (index) { | ||
63 | case 1: | ||
64 | if (val) | ||
65 | GPSR0 |= (1 << GPSR0_OFFSET(pin)); | ||
66 | else | ||
67 | GPCR0 |= (1 << GPCR0_OFFSET(pin)); | ||
68 | break; | ||
69 | case 2: | ||
70 | break; | ||
71 | case 3: | ||
72 | if (val) | ||
73 | GPSR1 |= (1 << GPSR1_OFFSET(pin)); | ||
74 | else | ||
75 | GPCR1 |= (1 << GPCR1_OFFSET(pin)); | ||
76 | break; | ||
77 | default: | ||
78 | printk(KERN_ERR "unimplemented\n"); | ||
79 | } | ||
80 | } | ||
81 | |||
82 | static void __devinit am200_init_gpio_pin(int pin, int dir) | ||
83 | { | ||
84 | u8 index; | ||
85 | /* dir 0 is output, 1 is input | ||
86 | - do 2 things here: | ||
87 | - set gpio alternate function to standard gpio | ||
88 | - set gpio direction to input or output */ | ||
89 | |||
90 | index = pin >> 4; | ||
91 | switch (index) { | ||
92 | case 1: | ||
93 | GAFR0_U &= ~(AF_SEL_GPIO_N << GAFR0_U_OFFSET(pin)); | ||
94 | |||
95 | if (dir) | ||
96 | GPDR0 &= ~(1 << pin); | ||
97 | else | ||
98 | GPDR0 |= (1 << pin); | ||
99 | break; | ||
100 | case 2: | ||
101 | GAFR1_L &= ~(AF_SEL_GPIO_N << GAFR1_L_OFFSET(pin)); | ||
102 | |||
103 | if (dir) | ||
104 | GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); | ||
105 | else | ||
106 | GPDR1 |= (1 << GPDR1_OFFSET(pin)); | ||
107 | break; | ||
108 | case 3: | ||
109 | GAFR1_U &= ~(AF_SEL_GPIO_N << GAFR1_U_OFFSET(pin)); | ||
110 | |||
111 | if (dir) | ||
112 | GPDR1 &= ~(1 << GPDR1_OFFSET(pin)); | ||
113 | else | ||
114 | GPDR1 |= (1 << GPDR1_OFFSET(pin)); | ||
115 | break; | ||
116 | default: | ||
117 | printk(KERN_ERR "unimplemented\n"); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | static void am200_init_gpio_regs(struct metronomefb_par *par) | ||
122 | { | ||
123 | am200_init_gpio_pin(LED_GPIO_PIN, 0); | ||
124 | am200_set_gpio_output(LED_GPIO_PIN, 0); | ||
125 | |||
126 | am200_init_gpio_pin(STDBY_GPIO_PIN, 0); | ||
127 | am200_set_gpio_output(STDBY_GPIO_PIN, 0); | ||
128 | |||
129 | am200_init_gpio_pin(RST_GPIO_PIN, 0); | ||
130 | am200_set_gpio_output(RST_GPIO_PIN, 0); | ||
131 | |||
132 | am200_init_gpio_pin(RDY_GPIO_PIN, 1); | ||
133 | |||
134 | am200_init_gpio_pin(ERR_GPIO_PIN, 1); | ||
135 | |||
136 | am200_init_gpio_pin(PCBPWR_GPIO_PIN, 0); | ||
137 | am200_set_gpio_output(PCBPWR_GPIO_PIN, 0); | ||
138 | } | ||
139 | |||
140 | static void am200_disable_lcd_controller(struct metronomefb_par *par) | ||
141 | { | ||
142 | LCSR = 0xffffffff; /* Clear LCD Status Register */ | ||
143 | LCCR0 |= LCCR0_DIS; /* Disable LCD Controller */ | ||
144 | |||
145 | /* we reset and just wait for things to settle */ | ||
146 | msleep(200); | ||
147 | } | ||
148 | |||
149 | static void am200_enable_lcd_controller(struct metronomefb_par *par) | ||
150 | { | ||
151 | LCSR = 0xffffffff; | ||
152 | FDADR0 = par->metromem_desc_dma; | ||
153 | LCCR0 |= LCCR0_ENB; | ||
154 | } | ||
155 | |||
156 | static void am200_init_lcdc_regs(struct metronomefb_par *par) | ||
157 | { | ||
158 | /* here we do: | ||
159 | - disable the lcd controller | ||
160 | - setup lcd control registers | ||
161 | - setup dma descriptor | ||
162 | - reenable lcd controller | ||
163 | */ | ||
164 | |||
165 | /* disable the lcd controller */ | ||
166 | am200_disable_lcd_controller(par); | ||
167 | |||
168 | /* setup lcd control registers */ | ||
169 | LCCR0 = LCCR0_LDM | LCCR0_SFM | LCCR0_IUM | LCCR0_EFM | LCCR0_PAS | ||
170 | | LCCR0_QDM | LCCR0_BM | LCCR0_OUM; | ||
171 | |||
172 | LCCR1 = (par->info->var.xres/2 - 1) /* pixels per line */ | ||
173 | | (27 << 10) /* hsync pulse width - 1 */ | ||
174 | | (33 << 16) /* eol pixel count */ | ||
175 | | (33 << 24); /* bol pixel count */ | ||
176 | |||
177 | LCCR2 = (par->info->var.yres - 1) /* lines per panel */ | ||
178 | | (24 << 10) /* vsync pulse width - 1 */ | ||
179 | | (2 << 16) /* eof pixel count */ | ||
180 | | (0 << 24); /* bof pixel count */ | ||
181 | |||
182 | LCCR3 = 2 /* pixel clock divisor */ | ||
183 | | (24 << 8) /* AC Bias pin freq */ | ||
184 | | LCCR3_16BPP /* BPP */ | ||
185 | | LCCR3_PCP; /* PCP falling edge */ | ||
186 | |||
187 | } | ||
188 | |||
189 | static void am200_post_dma_setup(struct metronomefb_par *par) | ||
190 | { | ||
191 | par->metromem_desc->mFDADR0 = par->metromem_desc_dma; | ||
192 | par->metromem_desc->mFSADR0 = par->metromem_dma; | ||
193 | par->metromem_desc->mFIDR0 = 0; | ||
194 | par->metromem_desc->mLDCMD0 = par->info->var.xres | ||
195 | * par->info->var.yres; | ||
196 | am200_enable_lcd_controller(par); | ||
197 | } | ||
198 | |||
199 | static void am200_free_irq(struct fb_info *info) | ||
200 | { | ||
201 | free_irq(IRQ_GPIO(RDY_GPIO_PIN), info); | ||
202 | } | ||
203 | |||
204 | static irqreturn_t am200_handle_irq(int irq, void *dev_id) | ||
205 | { | ||
206 | struct fb_info *info = dev_id; | ||
207 | struct metronomefb_par *par = info->par; | ||
208 | |||
209 | wake_up_interruptible(&par->waitq); | ||
210 | return IRQ_HANDLED; | ||
211 | } | ||
212 | |||
213 | static int am200_setup_irq(struct fb_info *info) | ||
214 | { | ||
215 | int retval; | ||
216 | |||
217 | retval = request_irq(IRQ_GPIO(RDY_GPIO_PIN), am200_handle_irq, | ||
218 | IRQF_DISABLED, "AM200", info); | ||
219 | if (retval) { | ||
220 | printk(KERN_ERR "am200epd: request_irq failed: %d\n", retval); | ||
221 | return retval; | ||
222 | } | ||
223 | |||
224 | return set_irq_type(IRQ_GPIO(RDY_GPIO_PIN), IRQ_TYPE_EDGE_FALLING); | ||
225 | } | ||
226 | |||
227 | static void am200_set_rst(struct metronomefb_par *par, int state) | ||
228 | { | ||
229 | am200_set_gpio_output(RST_GPIO_PIN, state); | ||
230 | } | ||
231 | |||
232 | static void am200_set_stdby(struct metronomefb_par *par, int state) | ||
233 | { | ||
234 | am200_set_gpio_output(STDBY_GPIO_PIN, state); | ||
235 | } | ||
236 | |||
237 | static int am200_wait_event(struct metronomefb_par *par) | ||
238 | { | ||
239 | return wait_event_timeout(par->waitq, (GPLR1 & 0x01), HZ); | ||
240 | } | ||
241 | |||
242 | static int am200_wait_event_intr(struct metronomefb_par *par) | ||
243 | { | ||
244 | return wait_event_interruptible_timeout(par->waitq, (GPLR1 & 0x01), HZ); | ||
245 | } | ||
246 | |||
247 | static struct metronome_board am200_board = { | ||
248 | .owner = THIS_MODULE, | ||
249 | .free_irq = am200_free_irq, | ||
250 | .setup_irq = am200_setup_irq, | ||
251 | .init_gpio_regs = am200_init_gpio_regs, | ||
252 | .init_lcdc_regs = am200_init_lcdc_regs, | ||
253 | .post_dma_setup = am200_post_dma_setup, | ||
254 | .set_rst = am200_set_rst, | ||
255 | .set_stdby = am200_set_stdby, | ||
256 | .met_wait_event = am200_wait_event, | ||
257 | .met_wait_event_intr = am200_wait_event_intr, | ||
258 | }; | ||
259 | |||
260 | static struct platform_device *am200_device; | ||
261 | |||
262 | static int __init am200_init(void) | ||
263 | { | ||
264 | int ret; | ||
265 | |||
266 | /* request our platform independent driver */ | ||
267 | request_module("metronomefb"); | ||
268 | |||
269 | am200_device = platform_device_alloc("metronomefb", -1); | ||
270 | if (!am200_device) | ||
271 | return -ENOMEM; | ||
272 | |||
273 | platform_device_add_data(am200_device, &am200_board, | ||
274 | sizeof(am200_board)); | ||
275 | |||
276 | /* this _add binds metronomefb to am200. metronomefb refcounts am200 */ | ||
277 | ret = platform_device_add(am200_device); | ||
278 | |||
279 | if (ret) | ||
280 | platform_device_put(am200_device); | ||
281 | |||
282 | return ret; | ||
283 | } | ||
284 | |||
285 | static void __exit am200_exit(void) | ||
286 | { | ||
287 | platform_device_unregister(am200_device); | ||
288 | } | ||
289 | |||
290 | module_init(am200_init); | ||
291 | module_exit(am200_exit); | ||
292 | |||
293 | MODULE_DESCRIPTION("board driver for am200 metronome epd kit"); | ||
294 | MODULE_AUTHOR("Jaya Kumar"); | ||
295 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 452b770d8cc9..c72a13562954 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig | |||
@@ -24,6 +24,13 @@ config LCD_CLASS_DEVICE | |||
24 | To have support for your specific LCD panel you will have to | 24 | To have support for your specific LCD panel you will have to |
25 | select the proper drivers which depend on this option. | 25 | select the proper drivers which depend on this option. |
26 | 26 | ||
27 | config LCD_CORGI | ||
28 | tristate "LCD Panel support for SHARP corgi/spitz model" | ||
29 | depends on LCD_CLASS_DEVICE && SPI_MASTER && PXA_SHARPSL | ||
30 | help | ||
31 | Say y here to support the LCD panels usually found on SHARP | ||
32 | corgi (C7x0) and spitz (Cxx00) models. | ||
33 | |||
27 | config LCD_LTV350QV | 34 | config LCD_LTV350QV |
28 | tristate "Samsung LTV350QV LCD Panel" | 35 | tristate "Samsung LTV350QV LCD Panel" |
29 | depends on LCD_CLASS_DEVICE && SPI_MASTER | 36 | depends on LCD_CLASS_DEVICE && SPI_MASTER |
@@ -44,6 +51,14 @@ config LCD_ILI9320 | |||
44 | If you have a panel based on the ILI9320 controller chip | 51 | If you have a panel based on the ILI9320 controller chip |
45 | then say y to include a power driver for it. | 52 | then say y to include a power driver for it. |
46 | 53 | ||
54 | config LCD_TDO24M | ||
55 | tristate "Toppoly TDO24M LCD Panels support" | ||
56 | depends on LCD_CLASS_DEVICE && SPI_MASTER | ||
57 | default n | ||
58 | help | ||
59 | If you have a Toppoly TDO24M series LCD panel, say y here to | ||
60 | include the support for it. | ||
61 | |||
47 | config LCD_VGG2432A4 | 62 | config LCD_VGG2432A4 |
48 | tristate "VGG2432A4 LCM device support" | 63 | tristate "VGG2432A4 LCM device support" |
49 | depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER | 64 | depends on BACKLIGHT_LCD_SUPPORT && LCD_CLASS_DEVICE && SPI_MASTER |
diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile index b405aace803f..3ec551eb472c 100644 --- a/drivers/video/backlight/Makefile +++ b/drivers/video/backlight/Makefile | |||
@@ -1,10 +1,12 @@ | |||
1 | # Backlight & LCD drivers | 1 | # Backlight & LCD drivers |
2 | 2 | ||
3 | obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o | 3 | obj-$(CONFIG_LCD_CLASS_DEVICE) += lcd.o |
4 | obj-$(CONFIG_LCD_CORGI) += corgi_lcd.o | ||
4 | obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o | 5 | obj-$(CONFIG_LCD_LTV350QV) += ltv350qv.o |
5 | obj-$(CONFIG_LCD_ILI9320) += ili9320.o | 6 | obj-$(CONFIG_LCD_ILI9320) += ili9320.o |
6 | obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o | 7 | obj-$(CONFIG_LCD_PLATFORM) += platform_lcd.o |
7 | obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o | 8 | obj-$(CONFIG_LCD_VGG2432A4) += vgg2432a4.o |
9 | obj-$(CONFIG_LCD_TDO24M) += tdo24m.o | ||
8 | 10 | ||
9 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o | 11 | obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o |
10 | obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o | 12 | obj-$(CONFIG_BACKLIGHT_ATMEL_PWM) += atmel-pwm-bl.o |
diff --git a/drivers/video/backlight/corgi_lcd.c b/drivers/video/backlight/corgi_lcd.c new file mode 100644 index 000000000000..2afd47eefe74 --- /dev/null +++ b/drivers/video/backlight/corgi_lcd.c | |||
@@ -0,0 +1,641 @@ | |||
1 | /* | ||
2 | * LCD/Backlight Driver for Sharp Zaurus Handhelds (various models) | ||
3 | * | ||
4 | * Copyright (c) 2004-2006 Richard Purdie | ||
5 | * | ||
6 | * Based on Sharp's 2.4 Backlight Driver | ||
7 | * | ||
8 | * Copyright (c) 2008 Marvell International Ltd. | ||
9 | * Converted to SPI device based LCD/Backlight device driver | ||
10 | * by Eric Miao <eric.miao@marvell.com> | ||
11 | * | ||
12 | * This program is free software; you can redistribute it and/or modify | ||
13 | * it under the terms of the GNU General Public License version 2 as | ||
14 | * published by the Free Software Foundation. | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/module.h> | ||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/delay.h> | ||
22 | #include <linux/gpio.h> | ||
23 | #include <linux/fb.h> | ||
24 | #include <linux/lcd.h> | ||
25 | #include <linux/spi/spi.h> | ||
26 | #include <linux/spi/corgi_lcd.h> | ||
27 | #include <asm/mach/sharpsl_param.h> | ||
28 | |||
29 | #define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) | ||
30 | |||
31 | /* Register Addresses */ | ||
32 | #define RESCTL_ADRS 0x00 | ||
33 | #define PHACTRL_ADRS 0x01 | ||
34 | #define DUTYCTRL_ADRS 0x02 | ||
35 | #define POWERREG0_ADRS 0x03 | ||
36 | #define POWERREG1_ADRS 0x04 | ||
37 | #define GPOR3_ADRS 0x05 | ||
38 | #define PICTRL_ADRS 0x06 | ||
39 | #define POLCTRL_ADRS 0x07 | ||
40 | |||
41 | /* Register Bit Definitions */ | ||
42 | #define RESCTL_QVGA 0x01 | ||
43 | #define RESCTL_VGA 0x00 | ||
44 | |||
45 | #define POWER1_VW_ON 0x01 /* VW Supply FET ON */ | ||
46 | #define POWER1_GVSS_ON 0x02 /* GVSS(-8V) Power Supply ON */ | ||
47 | #define POWER1_VDD_ON 0x04 /* VDD(8V),SVSS(-4V) Power Supply ON */ | ||
48 | |||
49 | #define POWER1_VW_OFF 0x00 /* VW Supply FET OFF */ | ||
50 | #define POWER1_GVSS_OFF 0x00 /* GVSS(-8V) Power Supply OFF */ | ||
51 | #define POWER1_VDD_OFF 0x00 /* VDD(8V),SVSS(-4V) Power Supply OFF */ | ||
52 | |||
53 | #define POWER0_COM_DCLK 0x01 /* COM Voltage DC Bias DAC Serial Data Clock */ | ||
54 | #define POWER0_COM_DOUT 0x02 /* COM Voltage DC Bias DAC Serial Data Out */ | ||
55 | #define POWER0_DAC_ON 0x04 /* DAC Power Supply ON */ | ||
56 | #define POWER0_COM_ON 0x08 /* COM Power Supply ON */ | ||
57 | #define POWER0_VCC5_ON 0x10 /* VCC5 Power Supply ON */ | ||
58 | |||
59 | #define POWER0_DAC_OFF 0x00 /* DAC Power Supply OFF */ | ||
60 | #define POWER0_COM_OFF 0x00 /* COM Power Supply OFF */ | ||
61 | #define POWER0_VCC5_OFF 0x00 /* VCC5 Power Supply OFF */ | ||
62 | |||
63 | #define PICTRL_INIT_STATE 0x01 | ||
64 | #define PICTRL_INIOFF 0x02 | ||
65 | #define PICTRL_POWER_DOWN 0x04 | ||
66 | #define PICTRL_COM_SIGNAL_OFF 0x08 | ||
67 | #define PICTRL_DAC_SIGNAL_OFF 0x10 | ||
68 | |||
69 | #define POLCTRL_SYNC_POL_FALL 0x01 | ||
70 | #define POLCTRL_EN_POL_FALL 0x02 | ||
71 | #define POLCTRL_DATA_POL_FALL 0x04 | ||
72 | #define POLCTRL_SYNC_ACT_H 0x08 | ||
73 | #define POLCTRL_EN_ACT_L 0x10 | ||
74 | |||
75 | #define POLCTRL_SYNC_POL_RISE 0x00 | ||
76 | #define POLCTRL_EN_POL_RISE 0x00 | ||
77 | #define POLCTRL_DATA_POL_RISE 0x00 | ||
78 | #define POLCTRL_SYNC_ACT_L 0x00 | ||
79 | #define POLCTRL_EN_ACT_H 0x00 | ||
80 | |||
81 | #define PHACTRL_PHASE_MANUAL 0x01 | ||
82 | #define DEFAULT_PHAD_QVGA (9) | ||
83 | #define DEFAULT_COMADJ (125) | ||
84 | |||
85 | struct corgi_lcd { | ||
86 | struct spi_device *spi_dev; | ||
87 | struct lcd_device *lcd_dev; | ||
88 | struct backlight_device *bl_dev; | ||
89 | |||
90 | int limit_mask; | ||
91 | int intensity; | ||
92 | int power; | ||
93 | int mode; | ||
94 | char buf[2]; | ||
95 | |||
96 | int gpio_backlight_on; | ||
97 | int gpio_backlight_cont; | ||
98 | int gpio_backlight_cont_inverted; | ||
99 | |||
100 | void (*kick_battery)(void); | ||
101 | }; | ||
102 | |||
103 | static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int reg, uint8_t val); | ||
104 | |||
105 | static struct corgi_lcd *the_corgi_lcd; | ||
106 | static unsigned long corgibl_flags; | ||
107 | #define CORGIBL_SUSPENDED 0x01 | ||
108 | #define CORGIBL_BATTLOW 0x02 | ||
109 | |||
110 | /* | ||
111 | * This is only a psuedo I2C interface. We can't use the standard kernel | ||
112 | * routines as the interface is write only. We just assume the data is acked... | ||
113 | */ | ||
114 | static void lcdtg_ssp_i2c_send(struct corgi_lcd *lcd, uint8_t data) | ||
115 | { | ||
116 | corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, data); | ||
117 | udelay(10); | ||
118 | } | ||
119 | |||
120 | static void lcdtg_i2c_send_bit(struct corgi_lcd *lcd, uint8_t data) | ||
121 | { | ||
122 | lcdtg_ssp_i2c_send(lcd, data); | ||
123 | lcdtg_ssp_i2c_send(lcd, data | POWER0_COM_DCLK); | ||
124 | lcdtg_ssp_i2c_send(lcd, data); | ||
125 | } | ||
126 | |||
127 | static void lcdtg_i2c_send_start(struct corgi_lcd *lcd, uint8_t base) | ||
128 | { | ||
129 | lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT); | ||
130 | lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK); | ||
131 | lcdtg_ssp_i2c_send(lcd, base); | ||
132 | } | ||
133 | |||
134 | static void lcdtg_i2c_send_stop(struct corgi_lcd *lcd, uint8_t base) | ||
135 | { | ||
136 | lcdtg_ssp_i2c_send(lcd, base); | ||
137 | lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK); | ||
138 | lcdtg_ssp_i2c_send(lcd, base | POWER0_COM_DCLK | POWER0_COM_DOUT); | ||
139 | } | ||
140 | |||
141 | static void lcdtg_i2c_send_byte(struct corgi_lcd *lcd, | ||
142 | uint8_t base, uint8_t data) | ||
143 | { | ||
144 | int i; | ||
145 | for (i = 0; i < 8; i++) { | ||
146 | if (data & 0x80) | ||
147 | lcdtg_i2c_send_bit(lcd, base | POWER0_COM_DOUT); | ||
148 | else | ||
149 | lcdtg_i2c_send_bit(lcd, base); | ||
150 | data <<= 1; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | static void lcdtg_i2c_wait_ack(struct corgi_lcd *lcd, uint8_t base) | ||
155 | { | ||
156 | lcdtg_i2c_send_bit(lcd, base); | ||
157 | } | ||
158 | |||
159 | static void lcdtg_set_common_voltage(struct corgi_lcd *lcd, | ||
160 | uint8_t base_data, uint8_t data) | ||
161 | { | ||
162 | /* Set Common Voltage to M62332FP via I2C */ | ||
163 | lcdtg_i2c_send_start(lcd, base_data); | ||
164 | lcdtg_i2c_send_byte(lcd, base_data, 0x9c); | ||
165 | lcdtg_i2c_wait_ack(lcd, base_data); | ||
166 | lcdtg_i2c_send_byte(lcd, base_data, 0x00); | ||
167 | lcdtg_i2c_wait_ack(lcd, base_data); | ||
168 | lcdtg_i2c_send_byte(lcd, base_data, data); | ||
169 | lcdtg_i2c_wait_ack(lcd, base_data); | ||
170 | lcdtg_i2c_send_stop(lcd, base_data); | ||
171 | } | ||
172 | |||
173 | static int corgi_ssp_lcdtg_send(struct corgi_lcd *lcd, int adrs, uint8_t data) | ||
174 | { | ||
175 | struct spi_message msg; | ||
176 | struct spi_transfer xfer = { | ||
177 | .len = 1, | ||
178 | .cs_change = 1, | ||
179 | .tx_buf = lcd->buf, | ||
180 | }; | ||
181 | |||
182 | lcd->buf[0] = ((adrs & 0x07) << 5) | (data & 0x1f); | ||
183 | spi_message_init(&msg); | ||
184 | spi_message_add_tail(&xfer, &msg); | ||
185 | |||
186 | return spi_sync(lcd->spi_dev, &msg); | ||
187 | } | ||
188 | |||
189 | /* Set Phase Adjust */ | ||
190 | static void lcdtg_set_phadadj(struct corgi_lcd *lcd, int mode) | ||
191 | { | ||
192 | int adj; | ||
193 | |||
194 | switch(mode) { | ||
195 | case CORGI_LCD_MODE_VGA: | ||
196 | /* Setting for VGA */ | ||
197 | adj = sharpsl_param.phadadj; | ||
198 | adj = (adj < 0) ? PHACTRL_PHASE_MANUAL : | ||
199 | PHACTRL_PHASE_MANUAL | ((adj & 0xf) << 1); | ||
200 | break; | ||
201 | case CORGI_LCD_MODE_QVGA: | ||
202 | default: | ||
203 | /* Setting for QVGA */ | ||
204 | adj = (DEFAULT_PHAD_QVGA << 1) | PHACTRL_PHASE_MANUAL; | ||
205 | break; | ||
206 | } | ||
207 | |||
208 | corgi_ssp_lcdtg_send(lcd, PHACTRL_ADRS, adj); | ||
209 | } | ||
210 | |||
211 | static void corgi_lcd_power_on(struct corgi_lcd *lcd) | ||
212 | { | ||
213 | int comadj; | ||
214 | |||
215 | /* Initialize Internal Logic & Port */ | ||
216 | corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, | ||
217 | PICTRL_POWER_DOWN | PICTRL_INIOFF | | ||
218 | PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF | | ||
219 | PICTRL_DAC_SIGNAL_OFF); | ||
220 | |||
221 | corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, | ||
222 | POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_OFF | | ||
223 | POWER0_COM_OFF | POWER0_VCC5_OFF); | ||
224 | |||
225 | corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS, | ||
226 | POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF); | ||
227 | |||
228 | /* VDD(+8V), SVSS(-4V) ON */ | ||
229 | corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS, | ||
230 | POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON); | ||
231 | mdelay(3); | ||
232 | |||
233 | /* DAC ON */ | ||
234 | corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, | ||
235 | POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON | | ||
236 | POWER0_COM_OFF | POWER0_VCC5_OFF); | ||
237 | |||
238 | /* INIB = H, INI = L */ | ||
239 | /* PICTL[0] = H , PICTL[1] = PICTL[2] = PICTL[4] = L */ | ||
240 | corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, | ||
241 | PICTRL_INIT_STATE | PICTRL_COM_SIGNAL_OFF); | ||
242 | |||
243 | /* Set Common Voltage */ | ||
244 | comadj = sharpsl_param.comadj; | ||
245 | if (comadj < 0) | ||
246 | comadj = DEFAULT_COMADJ; | ||
247 | |||
248 | lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF | | ||
249 | POWER0_VCC5_OFF, comadj); | ||
250 | |||
251 | /* VCC5 ON, DAC ON */ | ||
252 | corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, | ||
253 | POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON | | ||
254 | POWER0_COM_OFF | POWER0_VCC5_ON); | ||
255 | |||
256 | /* GVSS(-8V) ON, VDD ON */ | ||
257 | corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS, | ||
258 | POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON); | ||
259 | mdelay(2); | ||
260 | |||
261 | /* COM SIGNAL ON (PICTL[3] = L) */ | ||
262 | corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_INIT_STATE); | ||
263 | |||
264 | /* COM ON, DAC ON, VCC5_ON */ | ||
265 | corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, | ||
266 | POWER0_COM_DCLK | POWER0_COM_DOUT | POWER0_DAC_ON | | ||
267 | POWER0_COM_ON | POWER0_VCC5_ON); | ||
268 | |||
269 | /* VW ON, GVSS ON, VDD ON */ | ||
270 | corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS, | ||
271 | POWER1_VW_ON | POWER1_GVSS_ON | POWER1_VDD_ON); | ||
272 | |||
273 | /* Signals output enable */ | ||
274 | corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, 0); | ||
275 | |||
276 | /* Set Phase Adjust */ | ||
277 | lcdtg_set_phadadj(lcd, lcd->mode); | ||
278 | |||
279 | /* Initialize for Input Signals from ATI */ | ||
280 | corgi_ssp_lcdtg_send(lcd, POLCTRL_ADRS, | ||
281 | POLCTRL_SYNC_POL_RISE | POLCTRL_EN_POL_RISE | | ||
282 | POLCTRL_DATA_POL_RISE | POLCTRL_SYNC_ACT_L | | ||
283 | POLCTRL_EN_ACT_H); | ||
284 | udelay(1000); | ||
285 | |||
286 | switch (lcd->mode) { | ||
287 | case CORGI_LCD_MODE_VGA: | ||
288 | corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA); | ||
289 | break; | ||
290 | case CORGI_LCD_MODE_QVGA: | ||
291 | default: | ||
292 | corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA); | ||
293 | break; | ||
294 | } | ||
295 | } | ||
296 | |||
297 | static void corgi_lcd_power_off(struct corgi_lcd *lcd) | ||
298 | { | ||
299 | /* 60Hz x 2 frame = 16.7msec x 2 = 33.4 msec */ | ||
300 | msleep(34); | ||
301 | |||
302 | /* (1)VW OFF */ | ||
303 | corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS, | ||
304 | POWER1_VW_OFF | POWER1_GVSS_ON | POWER1_VDD_ON); | ||
305 | |||
306 | /* (2)COM OFF */ | ||
307 | corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, PICTRL_COM_SIGNAL_OFF); | ||
308 | corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, | ||
309 | POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_ON); | ||
310 | |||
311 | /* (3)Set Common Voltage Bias 0V */ | ||
312 | lcdtg_set_common_voltage(lcd, POWER0_DAC_ON | POWER0_COM_OFF | | ||
313 | POWER0_VCC5_ON, 0); | ||
314 | |||
315 | /* (4)GVSS OFF */ | ||
316 | corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS, | ||
317 | POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_ON); | ||
318 | |||
319 | /* (5)VCC5 OFF */ | ||
320 | corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, | ||
321 | POWER0_DAC_ON | POWER0_COM_OFF | POWER0_VCC5_OFF); | ||
322 | |||
323 | /* (6)Set PDWN, INIOFF, DACOFF */ | ||
324 | corgi_ssp_lcdtg_send(lcd, PICTRL_ADRS, | ||
325 | PICTRL_INIOFF | PICTRL_DAC_SIGNAL_OFF | | ||
326 | PICTRL_POWER_DOWN | PICTRL_COM_SIGNAL_OFF); | ||
327 | |||
328 | /* (7)DAC OFF */ | ||
329 | corgi_ssp_lcdtg_send(lcd, POWERREG0_ADRS, | ||
330 | POWER0_DAC_OFF | POWER0_COM_OFF | POWER0_VCC5_OFF); | ||
331 | |||
332 | /* (8)VDD OFF */ | ||
333 | corgi_ssp_lcdtg_send(lcd, POWERREG1_ADRS, | ||
334 | POWER1_VW_OFF | POWER1_GVSS_OFF | POWER1_VDD_OFF); | ||
335 | } | ||
336 | |||
337 | static int corgi_lcd_set_mode(struct lcd_device *ld, struct fb_videomode *m) | ||
338 | { | ||
339 | struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); | ||
340 | int mode = CORGI_LCD_MODE_QVGA; | ||
341 | |||
342 | if (m->xres == 640 || m->xres == 480) | ||
343 | mode = CORGI_LCD_MODE_VGA; | ||
344 | |||
345 | if (lcd->mode == mode) | ||
346 | return 0; | ||
347 | |||
348 | lcdtg_set_phadadj(lcd, mode); | ||
349 | |||
350 | switch (mode) { | ||
351 | case CORGI_LCD_MODE_VGA: | ||
352 | corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_VGA); | ||
353 | break; | ||
354 | case CORGI_LCD_MODE_QVGA: | ||
355 | default: | ||
356 | corgi_ssp_lcdtg_send(lcd, RESCTL_ADRS, RESCTL_QVGA); | ||
357 | break; | ||
358 | } | ||
359 | |||
360 | lcd->mode = mode; | ||
361 | return 0; | ||
362 | } | ||
363 | |||
364 | static int corgi_lcd_set_power(struct lcd_device *ld, int power) | ||
365 | { | ||
366 | struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); | ||
367 | |||
368 | if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) | ||
369 | corgi_lcd_power_on(lcd); | ||
370 | |||
371 | if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) | ||
372 | corgi_lcd_power_off(lcd); | ||
373 | |||
374 | lcd->power = power; | ||
375 | return 0; | ||
376 | } | ||
377 | |||
378 | static int corgi_lcd_get_power(struct lcd_device *ld) | ||
379 | { | ||
380 | struct corgi_lcd *lcd = dev_get_drvdata(&ld->dev); | ||
381 | |||
382 | return lcd->power; | ||
383 | } | ||
384 | |||
385 | static struct lcd_ops corgi_lcd_ops = { | ||
386 | .get_power = corgi_lcd_get_power, | ||
387 | .set_power = corgi_lcd_set_power, | ||
388 | .set_mode = corgi_lcd_set_mode, | ||
389 | }; | ||
390 | |||
391 | static int corgi_bl_get_intensity(struct backlight_device *bd) | ||
392 | { | ||
393 | struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev); | ||
394 | |||
395 | return lcd->intensity; | ||
396 | } | ||
397 | |||
398 | static int corgi_bl_set_intensity(struct corgi_lcd *lcd, int intensity) | ||
399 | { | ||
400 | int cont; | ||
401 | |||
402 | if (intensity > 0x10) | ||
403 | intensity += 0x10; | ||
404 | |||
405 | corgi_ssp_lcdtg_send(lcd, DUTYCTRL_ADRS, intensity); | ||
406 | |||
407 | /* Bit 5 via GPIO_BACKLIGHT_CONT */ | ||
408 | cont = !!(intensity & 0x20) ^ lcd->gpio_backlight_cont_inverted; | ||
409 | |||
410 | if (gpio_is_valid(lcd->gpio_backlight_cont)) | ||
411 | gpio_set_value(lcd->gpio_backlight_cont, cont); | ||
412 | |||
413 | if (gpio_is_valid(lcd->gpio_backlight_on)) | ||
414 | gpio_set_value(lcd->gpio_backlight_on, intensity); | ||
415 | |||
416 | if (lcd->kick_battery) | ||
417 | lcd->kick_battery(); | ||
418 | |||
419 | lcd->intensity = intensity; | ||
420 | return 0; | ||
421 | } | ||
422 | |||
423 | static int corgi_bl_update_status(struct backlight_device *bd) | ||
424 | { | ||
425 | struct corgi_lcd *lcd = dev_get_drvdata(&bd->dev); | ||
426 | int intensity = bd->props.brightness; | ||
427 | |||
428 | if (bd->props.power != FB_BLANK_UNBLANK) | ||
429 | intensity = 0; | ||
430 | |||
431 | if (bd->props.fb_blank != FB_BLANK_UNBLANK) | ||
432 | intensity = 0; | ||
433 | |||
434 | if (corgibl_flags & CORGIBL_SUSPENDED) | ||
435 | intensity = 0; | ||
436 | if (corgibl_flags & CORGIBL_BATTLOW) | ||
437 | intensity &= lcd->limit_mask; | ||
438 | |||
439 | return corgi_bl_set_intensity(lcd, intensity); | ||
440 | } | ||
441 | |||
442 | void corgibl_limit_intensity(int limit) | ||
443 | { | ||
444 | if (limit) | ||
445 | corgibl_flags |= CORGIBL_BATTLOW; | ||
446 | else | ||
447 | corgibl_flags &= ~CORGIBL_BATTLOW; | ||
448 | |||
449 | backlight_update_status(the_corgi_lcd->bl_dev); | ||
450 | } | ||
451 | EXPORT_SYMBOL(corgibl_limit_intensity); | ||
452 | |||
453 | static struct backlight_ops corgi_bl_ops = { | ||
454 | .get_brightness = corgi_bl_get_intensity, | ||
455 | .update_status = corgi_bl_update_status, | ||
456 | }; | ||
457 | |||
458 | #ifdef CONFIG_PM | ||
459 | static int corgi_lcd_suspend(struct spi_device *spi, pm_message_t state) | ||
460 | { | ||
461 | struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); | ||
462 | |||
463 | corgibl_flags |= CORGIBL_SUSPENDED; | ||
464 | corgi_bl_set_intensity(lcd, 0); | ||
465 | corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN); | ||
466 | return 0; | ||
467 | } | ||
468 | |||
469 | static int corgi_lcd_resume(struct spi_device *spi) | ||
470 | { | ||
471 | struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); | ||
472 | |||
473 | corgibl_flags &= ~CORGIBL_SUSPENDED; | ||
474 | corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK); | ||
475 | backlight_update_status(lcd->bl_dev); | ||
476 | return 0; | ||
477 | } | ||
478 | #else | ||
479 | #define corgi_lcd_suspend NULL | ||
480 | #define corgi_lcd_resume NULL | ||
481 | #endif | ||
482 | |||
483 | static int setup_gpio_backlight(struct corgi_lcd *lcd, | ||
484 | struct corgi_lcd_platform_data *pdata) | ||
485 | { | ||
486 | struct spi_device *spi = lcd->spi_dev; | ||
487 | int err; | ||
488 | |||
489 | lcd->gpio_backlight_on = -1; | ||
490 | lcd->gpio_backlight_cont = -1; | ||
491 | |||
492 | if (gpio_is_valid(pdata->gpio_backlight_on)) { | ||
493 | err = gpio_request(pdata->gpio_backlight_on, "BL_ON"); | ||
494 | if (err) { | ||
495 | dev_err(&spi->dev, "failed to request GPIO%d for " | ||
496 | "backlight_on\n", pdata->gpio_backlight_on); | ||
497 | return err; | ||
498 | } | ||
499 | |||
500 | lcd->gpio_backlight_on = pdata->gpio_backlight_on; | ||
501 | gpio_direction_output(lcd->gpio_backlight_on, 0); | ||
502 | } | ||
503 | |||
504 | if (gpio_is_valid(pdata->gpio_backlight_cont)) { | ||
505 | err = gpio_request(pdata->gpio_backlight_cont, "BL_CONT"); | ||
506 | if (err) { | ||
507 | dev_err(&spi->dev, "failed to request GPIO%d for " | ||
508 | "backlight_cont\n", pdata->gpio_backlight_cont); | ||
509 | goto err_free_backlight_on; | ||
510 | } | ||
511 | |||
512 | lcd->gpio_backlight_cont = pdata->gpio_backlight_cont; | ||
513 | |||
514 | /* spitz and akita use both GPIOs for backlight, and | ||
515 | * have inverted polarity of GPIO_BACKLIGHT_CONT | ||
516 | */ | ||
517 | if (gpio_is_valid(lcd->gpio_backlight_on)) { | ||
518 | lcd->gpio_backlight_cont_inverted = 1; | ||
519 | gpio_direction_output(lcd->gpio_backlight_cont, 1); | ||
520 | } else { | ||
521 | lcd->gpio_backlight_cont_inverted = 0; | ||
522 | gpio_direction_output(lcd->gpio_backlight_cont, 0); | ||
523 | } | ||
524 | } | ||
525 | return 0; | ||
526 | |||
527 | err_free_backlight_on: | ||
528 | if (gpio_is_valid(lcd->gpio_backlight_on)) | ||
529 | gpio_free(lcd->gpio_backlight_on); | ||
530 | return err; | ||
531 | } | ||
532 | |||
533 | static int __devinit corgi_lcd_probe(struct spi_device *spi) | ||
534 | { | ||
535 | struct corgi_lcd_platform_data *pdata = spi->dev.platform_data; | ||
536 | struct corgi_lcd *lcd; | ||
537 | int ret = 0; | ||
538 | |||
539 | if (pdata == NULL) { | ||
540 | dev_err(&spi->dev, "platform data not available\n"); | ||
541 | return -EINVAL; | ||
542 | } | ||
543 | |||
544 | lcd = kzalloc(sizeof(struct corgi_lcd), GFP_KERNEL); | ||
545 | if (!lcd) { | ||
546 | dev_err(&spi->dev, "failed to allocate memory\n"); | ||
547 | return -ENOMEM; | ||
548 | } | ||
549 | |||
550 | lcd->spi_dev = spi; | ||
551 | |||
552 | lcd->lcd_dev = lcd_device_register("corgi_lcd", &spi->dev, | ||
553 | lcd, &corgi_lcd_ops); | ||
554 | if (IS_ERR(lcd->lcd_dev)) { | ||
555 | ret = PTR_ERR(lcd->lcd_dev); | ||
556 | goto err_free_lcd; | ||
557 | } | ||
558 | lcd->power = FB_BLANK_POWERDOWN; | ||
559 | lcd->mode = (pdata) ? pdata->init_mode : CORGI_LCD_MODE_VGA; | ||
560 | |||
561 | lcd->bl_dev = backlight_device_register("corgi_bl", &spi->dev, | ||
562 | lcd, &corgi_bl_ops); | ||
563 | if (IS_ERR(lcd->bl_dev)) { | ||
564 | ret = PTR_ERR(lcd->bl_dev); | ||
565 | goto err_unregister_lcd; | ||
566 | } | ||
567 | lcd->bl_dev->props.max_brightness = pdata->max_intensity; | ||
568 | lcd->bl_dev->props.brightness = pdata->default_intensity; | ||
569 | lcd->bl_dev->props.power = FB_BLANK_UNBLANK; | ||
570 | |||
571 | ret = setup_gpio_backlight(lcd, pdata); | ||
572 | if (ret) | ||
573 | goto err_unregister_bl; | ||
574 | |||
575 | lcd->kick_battery = pdata->kick_battery; | ||
576 | |||
577 | dev_set_drvdata(&spi->dev, lcd); | ||
578 | corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_UNBLANK); | ||
579 | backlight_update_status(lcd->bl_dev); | ||
580 | |||
581 | lcd->limit_mask = pdata->limit_mask; | ||
582 | the_corgi_lcd = lcd; | ||
583 | return 0; | ||
584 | |||
585 | err_unregister_bl: | ||
586 | backlight_device_unregister(lcd->bl_dev); | ||
587 | err_unregister_lcd: | ||
588 | lcd_device_unregister(lcd->lcd_dev); | ||
589 | err_free_lcd: | ||
590 | kfree(lcd); | ||
591 | return ret; | ||
592 | } | ||
593 | |||
594 | static int __devexit corgi_lcd_remove(struct spi_device *spi) | ||
595 | { | ||
596 | struct corgi_lcd *lcd = dev_get_drvdata(&spi->dev); | ||
597 | |||
598 | lcd->bl_dev->props.power = FB_BLANK_UNBLANK; | ||
599 | lcd->bl_dev->props.brightness = 0; | ||
600 | backlight_update_status(lcd->bl_dev); | ||
601 | backlight_device_unregister(lcd->bl_dev); | ||
602 | |||
603 | if (gpio_is_valid(lcd->gpio_backlight_on)) | ||
604 | gpio_free(lcd->gpio_backlight_on); | ||
605 | |||
606 | if (gpio_is_valid(lcd->gpio_backlight_cont)) | ||
607 | gpio_free(lcd->gpio_backlight_cont); | ||
608 | |||
609 | corgi_lcd_set_power(lcd->lcd_dev, FB_BLANK_POWERDOWN); | ||
610 | lcd_device_unregister(lcd->lcd_dev); | ||
611 | kfree(lcd); | ||
612 | |||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static struct spi_driver corgi_lcd_driver = { | ||
617 | .driver = { | ||
618 | .name = "corgi-lcd", | ||
619 | .owner = THIS_MODULE, | ||
620 | }, | ||
621 | .probe = corgi_lcd_probe, | ||
622 | .remove = __devexit_p(corgi_lcd_remove), | ||
623 | .suspend = corgi_lcd_suspend, | ||
624 | .resume = corgi_lcd_resume, | ||
625 | }; | ||
626 | |||
627 | static int __init corgi_lcd_init(void) | ||
628 | { | ||
629 | return spi_register_driver(&corgi_lcd_driver); | ||
630 | } | ||
631 | module_init(corgi_lcd_init); | ||
632 | |||
633 | static void __exit corgi_lcd_exit(void) | ||
634 | { | ||
635 | spi_unregister_driver(&corgi_lcd_driver); | ||
636 | } | ||
637 | module_exit(corgi_lcd_exit); | ||
638 | |||
639 | MODULE_DESCRIPTION("LCD and backlight driver for SHARP C7x0/Cxx00"); | ||
640 | MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"); | ||
641 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c index b15b2b84a6f7..8e1731d3b228 100644 --- a/drivers/video/backlight/lcd.c +++ b/drivers/video/backlight/lcd.c | |||
@@ -27,14 +27,26 @@ static int fb_notifier_callback(struct notifier_block *self, | |||
27 | struct fb_event *evdata = data; | 27 | struct fb_event *evdata = data; |
28 | 28 | ||
29 | /* If we aren't interested in this event, skip it immediately ... */ | 29 | /* If we aren't interested in this event, skip it immediately ... */ |
30 | if (event != FB_EVENT_BLANK) | 30 | switch (event) { |
31 | case FB_EVENT_BLANK: | ||
32 | case FB_EVENT_MODE_CHANGE: | ||
33 | case FB_EVENT_MODE_CHANGE_ALL: | ||
34 | break; | ||
35 | default: | ||
31 | return 0; | 36 | return 0; |
37 | } | ||
32 | 38 | ||
33 | ld = container_of(self, struct lcd_device, fb_notif); | 39 | ld = container_of(self, struct lcd_device, fb_notif); |
40 | if (!ld->ops) | ||
41 | return 0; | ||
42 | |||
34 | mutex_lock(&ld->ops_lock); | 43 | mutex_lock(&ld->ops_lock); |
35 | if (ld->ops) | 44 | if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) { |
36 | if (!ld->ops->check_fb || ld->ops->check_fb(ld, evdata->info)) | 45 | if (event == FB_EVENT_BLANK) |
37 | ld->ops->set_power(ld, *(int *)evdata->data); | 46 | ld->ops->set_power(ld, *(int *)evdata->data); |
47 | else | ||
48 | ld->ops->set_mode(ld, evdata->data); | ||
49 | } | ||
38 | mutex_unlock(&ld->ops_lock); | 50 | mutex_unlock(&ld->ops_lock); |
39 | return 0; | 51 | return 0; |
40 | } | 52 | } |
diff --git a/drivers/video/backlight/tdo24m.c b/drivers/video/backlight/tdo24m.c new file mode 100644 index 000000000000..8427669162ea --- /dev/null +++ b/drivers/video/backlight/tdo24m.c | |||
@@ -0,0 +1,396 @@ | |||
1 | /* | ||
2 | * tdo24m - SPI-based drivers for Toppoly TDO24M series LCD panels | ||
3 | * | ||
4 | * Copyright (C) 2008 Marvell International Ltd. | ||
5 | * Eric Miao <eric.miao@marvell.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify | ||
8 | * it under the terms of the GNU General Public License version 2 as | ||
9 | * publishhed by the Free Software Foundation. | ||
10 | */ | ||
11 | |||
12 | #include <linux/module.h> | ||
13 | #include <linux/kernel.h> | ||
14 | #include <linux/init.h> | ||
15 | #include <linux/device.h> | ||
16 | #include <linux/spi/spi.h> | ||
17 | #include <linux/fb.h> | ||
18 | #include <linux/lcd.h> | ||
19 | |||
20 | #define POWER_IS_ON(pwr) ((pwr) <= FB_BLANK_NORMAL) | ||
21 | |||
22 | #define TDO24M_SPI_BUFF_SIZE (4) | ||
23 | #define MODE_QVGA 0 | ||
24 | #define MODE_VGA 1 | ||
25 | |||
26 | struct tdo24m { | ||
27 | struct spi_device *spi_dev; | ||
28 | struct lcd_device *lcd_dev; | ||
29 | |||
30 | struct spi_message msg; | ||
31 | struct spi_transfer xfer; | ||
32 | uint8_t *buf; | ||
33 | |||
34 | int power; | ||
35 | int mode; | ||
36 | }; | ||
37 | |||
38 | /* use bit 30, 31 as the indicator of command parameter number */ | ||
39 | #define CMD0(x) ((0 << 30) | (x)) | ||
40 | #define CMD1(x, x1) ((1 << 30) | ((x) << 9) | 0x100 | (x1)) | ||
41 | #define CMD2(x, x1, x2) ((2 << 30) | ((x) << 18) | 0x20000 |\ | ||
42 | ((x1) << 9) | 0x100 | (x2)) | ||
43 | #define CMD_NULL (-1) | ||
44 | |||
45 | static uint32_t lcd_panel_reset[] = { | ||
46 | CMD0(0x1), /* reset */ | ||
47 | CMD0(0x0), /* nop */ | ||
48 | CMD0(0x0), /* nop */ | ||
49 | CMD0(0x0), /* nop */ | ||
50 | CMD_NULL, | ||
51 | }; | ||
52 | |||
53 | static uint32_t lcd_panel_on[] = { | ||
54 | CMD0(0x29), /* Display ON */ | ||
55 | CMD2(0xB8, 0xFF, 0xF9), /* Output Control */ | ||
56 | CMD0(0x11), /* Sleep out */ | ||
57 | CMD1(0xB0, 0x16), /* Wake */ | ||
58 | CMD_NULL, | ||
59 | }; | ||
60 | |||
61 | static uint32_t lcd_panel_off[] = { | ||
62 | CMD0(0x28), /* Display OFF */ | ||
63 | CMD2(0xB8, 0x80, 0x02), /* Output Control */ | ||
64 | CMD0(0x10), /* Sleep in */ | ||
65 | CMD1(0xB0, 0x00), /* Deep stand by in */ | ||
66 | CMD_NULL, | ||
67 | }; | ||
68 | |||
69 | static uint32_t lcd_vga_pass_through[] = { | ||
70 | CMD1(0xB0, 0x16), | ||
71 | CMD1(0xBC, 0x80), | ||
72 | CMD1(0xE1, 0x00), | ||
73 | CMD1(0x36, 0x50), | ||
74 | CMD1(0x3B, 0x00), | ||
75 | CMD_NULL, | ||
76 | }; | ||
77 | |||
78 | static uint32_t lcd_qvga_pass_through[] = { | ||
79 | CMD1(0xB0, 0x16), | ||
80 | CMD1(0xBC, 0x81), | ||
81 | CMD1(0xE1, 0x00), | ||
82 | CMD1(0x36, 0x50), | ||
83 | CMD1(0x3B, 0x22), | ||
84 | CMD_NULL, | ||
85 | }; | ||
86 | |||
87 | static uint32_t lcd_vga_transfer[] = { | ||
88 | CMD1(0xcf, 0x02), /* Blanking period control (1) */ | ||
89 | CMD2(0xd0, 0x08, 0x04), /* Blanking period control (2) */ | ||
90 | CMD1(0xd1, 0x01), /* CKV timing control on/off */ | ||
91 | CMD2(0xd2, 0x14, 0x00), /* CKV 1,2 timing control */ | ||
92 | CMD2(0xd3, 0x1a, 0x0f), /* OEV timing control */ | ||
93 | CMD2(0xd4, 0x1f, 0xaf), /* ASW timing control (1) */ | ||
94 | CMD1(0xd5, 0x14), /* ASW timing control (2) */ | ||
95 | CMD0(0x21), /* Invert for normally black display */ | ||
96 | CMD0(0x29), /* Display on */ | ||
97 | CMD_NULL, | ||
98 | }; | ||
99 | |||
100 | static uint32_t lcd_qvga_transfer[] = { | ||
101 | CMD1(0xd6, 0x02), /* Blanking period control (1) */ | ||
102 | CMD2(0xd7, 0x08, 0x04), /* Blanking period control (2) */ | ||
103 | CMD1(0xd8, 0x01), /* CKV timing control on/off */ | ||
104 | CMD2(0xd9, 0x00, 0x08), /* CKV 1,2 timing control */ | ||
105 | CMD2(0xde, 0x05, 0x0a), /* OEV timing control */ | ||
106 | CMD2(0xdf, 0x0a, 0x19), /* ASW timing control (1) */ | ||
107 | CMD1(0xe0, 0x0a), /* ASW timing control (2) */ | ||
108 | CMD0(0x21), /* Invert for normally black display */ | ||
109 | CMD0(0x29), /* Display on */ | ||
110 | CMD_NULL, | ||
111 | }; | ||
112 | |||
113 | static uint32_t lcd_panel_config[] = { | ||
114 | CMD2(0xb8, 0xff, 0xf9), /* Output control */ | ||
115 | CMD0(0x11), /* sleep out */ | ||
116 | CMD1(0xba, 0x01), /* Display mode (1) */ | ||
117 | CMD1(0xbb, 0x00), /* Display mode (2) */ | ||
118 | CMD1(0x3a, 0x60), /* Display mode 18-bit RGB */ | ||
119 | CMD1(0xbf, 0x10), /* Drive system change control */ | ||
120 | CMD1(0xb1, 0x56), /* Booster operation setup */ | ||
121 | CMD1(0xb2, 0x33), /* Booster mode setup */ | ||
122 | CMD1(0xb3, 0x11), /* Booster frequency setup */ | ||
123 | CMD1(0xb4, 0x02), /* Op amp/system clock */ | ||
124 | CMD1(0xb5, 0x35), /* VCS voltage */ | ||
125 | CMD1(0xb6, 0x40), /* VCOM voltage */ | ||
126 | CMD1(0xb7, 0x03), /* External display signal */ | ||
127 | CMD1(0xbd, 0x00), /* ASW slew rate */ | ||
128 | CMD1(0xbe, 0x00), /* Dummy data for QuadData operation */ | ||
129 | CMD1(0xc0, 0x11), /* Sleep out FR count (A) */ | ||
130 | CMD1(0xc1, 0x11), /* Sleep out FR count (B) */ | ||
131 | CMD1(0xc2, 0x11), /* Sleep out FR count (C) */ | ||
132 | CMD2(0xc3, 0x20, 0x40), /* Sleep out FR count (D) */ | ||
133 | CMD2(0xc4, 0x60, 0xc0), /* Sleep out FR count (E) */ | ||
134 | CMD2(0xc5, 0x10, 0x20), /* Sleep out FR count (F) */ | ||
135 | CMD1(0xc6, 0xc0), /* Sleep out FR count (G) */ | ||
136 | CMD2(0xc7, 0x33, 0x43), /* Gamma 1 fine tuning (1) */ | ||
137 | CMD1(0xc8, 0x44), /* Gamma 1 fine tuning (2) */ | ||
138 | CMD1(0xc9, 0x33), /* Gamma 1 inclination adjustment */ | ||
139 | CMD1(0xca, 0x00), /* Gamma 1 blue offset adjustment */ | ||
140 | CMD2(0xec, 0x01, 0xf0), /* Horizontal clock cycles */ | ||
141 | CMD_NULL, | ||
142 | }; | ||
143 | |||
144 | static int tdo24m_writes(struct tdo24m *lcd, uint32_t *array) | ||
145 | { | ||
146 | struct spi_transfer *x = &lcd->xfer; | ||
147 | uint32_t data, *p = array; | ||
148 | int nparams, err = 0; | ||
149 | |||
150 | for (; *p != CMD_NULL; p++) { | ||
151 | |||
152 | nparams = (*p >> 30) & 0x3; | ||
153 | |||
154 | data = *p << (7 - nparams); | ||
155 | switch (nparams) { | ||
156 | case 0: | ||
157 | lcd->buf[0] = (data >> 8) & 0xff; | ||
158 | lcd->buf[1] = data & 0xff; | ||
159 | break; | ||
160 | case 1: | ||
161 | lcd->buf[0] = (data >> 16) & 0xff; | ||
162 | lcd->buf[1] = (data >> 8) & 0xff; | ||
163 | lcd->buf[2] = data & 0xff; | ||
164 | break; | ||
165 | case 2: | ||
166 | lcd->buf[0] = (data >> 24) & 0xff; | ||
167 | lcd->buf[1] = (data >> 16) & 0xff; | ||
168 | lcd->buf[2] = (data >> 8) & 0xff; | ||
169 | lcd->buf[3] = data & 0xff; | ||
170 | break; | ||
171 | default: | ||
172 | continue; | ||
173 | } | ||
174 | x->len = nparams + 2; | ||
175 | err = spi_sync(lcd->spi_dev, &lcd->msg); | ||
176 | if (err) | ||
177 | break; | ||
178 | } | ||
179 | |||
180 | return err; | ||
181 | } | ||
182 | |||
183 | static int tdo24m_adj_mode(struct tdo24m *lcd, int mode) | ||
184 | { | ||
185 | switch (mode) { | ||
186 | case MODE_VGA: | ||
187 | tdo24m_writes(lcd, lcd_vga_pass_through); | ||
188 | tdo24m_writes(lcd, lcd_panel_config); | ||
189 | tdo24m_writes(lcd, lcd_vga_transfer); | ||
190 | break; | ||
191 | case MODE_QVGA: | ||
192 | tdo24m_writes(lcd, lcd_qvga_pass_through); | ||
193 | tdo24m_writes(lcd, lcd_panel_config); | ||
194 | tdo24m_writes(lcd, lcd_qvga_transfer); | ||
195 | break; | ||
196 | default: | ||
197 | return -EINVAL; | ||
198 | } | ||
199 | |||
200 | lcd->mode = mode; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int tdo24m_power_on(struct tdo24m *lcd) | ||
205 | { | ||
206 | int err; | ||
207 | |||
208 | err = tdo24m_writes(lcd, lcd_panel_on); | ||
209 | if (err) | ||
210 | goto out; | ||
211 | |||
212 | err = tdo24m_writes(lcd, lcd_panel_reset); | ||
213 | if (err) | ||
214 | goto out; | ||
215 | |||
216 | err = tdo24m_adj_mode(lcd, lcd->mode); | ||
217 | out: | ||
218 | return err; | ||
219 | } | ||
220 | |||
221 | static int tdo24m_power_off(struct tdo24m *lcd) | ||
222 | { | ||
223 | return tdo24m_writes(lcd, lcd_panel_off); | ||
224 | } | ||
225 | |||
226 | static int tdo24m_power(struct tdo24m *lcd, int power) | ||
227 | { | ||
228 | int ret = 0; | ||
229 | |||
230 | if (POWER_IS_ON(power) && !POWER_IS_ON(lcd->power)) | ||
231 | ret = tdo24m_power_on(lcd); | ||
232 | else if (!POWER_IS_ON(power) && POWER_IS_ON(lcd->power)) | ||
233 | ret = tdo24m_power_off(lcd); | ||
234 | |||
235 | if (!ret) | ||
236 | lcd->power = power; | ||
237 | |||
238 | return ret; | ||
239 | } | ||
240 | |||
241 | |||
242 | static int tdo24m_set_power(struct lcd_device *ld, int power) | ||
243 | { | ||
244 | struct tdo24m *lcd = lcd_get_data(ld); | ||
245 | return tdo24m_power(lcd, power); | ||
246 | } | ||
247 | |||
248 | static int tdo24m_get_power(struct lcd_device *ld) | ||
249 | { | ||
250 | struct tdo24m *lcd = lcd_get_data(ld); | ||
251 | return lcd->power; | ||
252 | } | ||
253 | |||
254 | static int tdo24m_set_mode(struct lcd_device *ld, struct fb_videomode *m) | ||
255 | { | ||
256 | struct tdo24m *lcd = lcd_get_data(ld); | ||
257 | int mode = MODE_QVGA; | ||
258 | |||
259 | if (m->xres == 640 || m->xres == 480) | ||
260 | mode = MODE_VGA; | ||
261 | |||
262 | if (lcd->mode == mode) | ||
263 | return 0; | ||
264 | |||
265 | return tdo24m_adj_mode(lcd, mode); | ||
266 | } | ||
267 | |||
268 | static struct lcd_ops tdo24m_ops = { | ||
269 | .get_power = tdo24m_get_power, | ||
270 | .set_power = tdo24m_set_power, | ||
271 | .set_mode = tdo24m_set_mode, | ||
272 | }; | ||
273 | |||
274 | static int __devinit tdo24m_probe(struct spi_device *spi) | ||
275 | { | ||
276 | struct tdo24m *lcd; | ||
277 | struct spi_message *m; | ||
278 | struct spi_transfer *x; | ||
279 | int err; | ||
280 | |||
281 | spi->bits_per_word = 8; | ||
282 | spi->mode = SPI_MODE_3; | ||
283 | err = spi_setup(spi); | ||
284 | if (err) | ||
285 | return err; | ||
286 | |||
287 | lcd = kzalloc(sizeof(struct tdo24m), GFP_KERNEL); | ||
288 | if (!lcd) | ||
289 | return -ENOMEM; | ||
290 | |||
291 | lcd->spi_dev = spi; | ||
292 | lcd->power = FB_BLANK_POWERDOWN; | ||
293 | lcd->mode = MODE_VGA; /* default to VGA */ | ||
294 | |||
295 | lcd->buf = kmalloc(TDO24M_SPI_BUFF_SIZE, sizeof(GFP_KERNEL)); | ||
296 | if (lcd->buf == NULL) { | ||
297 | kfree(lcd); | ||
298 | return -ENOMEM; | ||
299 | } | ||
300 | |||
301 | m = &lcd->msg; | ||
302 | x = &lcd->xfer; | ||
303 | |||
304 | spi_message_init(m); | ||
305 | |||
306 | x->tx_buf = &lcd->buf[0]; | ||
307 | spi_message_add_tail(x, m); | ||
308 | |||
309 | lcd->lcd_dev = lcd_device_register("tdo24m", &spi->dev, | ||
310 | lcd, &tdo24m_ops); | ||
311 | if (IS_ERR(lcd->lcd_dev)) { | ||
312 | err = PTR_ERR(lcd->lcd_dev); | ||
313 | goto out_free; | ||
314 | } | ||
315 | |||
316 | dev_set_drvdata(&spi->dev, lcd); | ||
317 | err = tdo24m_power(lcd, FB_BLANK_UNBLANK); | ||
318 | if (err) | ||
319 | goto out_unregister; | ||
320 | |||
321 | return 0; | ||
322 | |||
323 | out_unregister: | ||
324 | lcd_device_unregister(lcd->lcd_dev); | ||
325 | out_free: | ||
326 | kfree(lcd->buf); | ||
327 | kfree(lcd); | ||
328 | return err; | ||
329 | } | ||
330 | |||
331 | static int __devexit tdo24m_remove(struct spi_device *spi) | ||
332 | { | ||
333 | struct tdo24m *lcd = dev_get_drvdata(&spi->dev); | ||
334 | |||
335 | tdo24m_power(lcd, FB_BLANK_POWERDOWN); | ||
336 | lcd_device_unregister(lcd->lcd_dev); | ||
337 | kfree(lcd->buf); | ||
338 | kfree(lcd); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | #ifdef CONFIG_PM | ||
344 | static int tdo24m_suspend(struct spi_device *spi, pm_message_t state) | ||
345 | { | ||
346 | struct tdo24m *lcd = dev_get_drvdata(&spi->dev); | ||
347 | |||
348 | return tdo24m_power(lcd, FB_BLANK_POWERDOWN); | ||
349 | } | ||
350 | |||
351 | static int tdo24m_resume(struct spi_device *spi) | ||
352 | { | ||
353 | struct tdo24m *lcd = dev_get_drvdata(&spi->dev); | ||
354 | |||
355 | return tdo24m_power(lcd, FB_BLANK_UNBLANK); | ||
356 | } | ||
357 | #else | ||
358 | #define tdo24m_suspend NULL | ||
359 | #define tdo24m_resume NULL | ||
360 | #endif | ||
361 | |||
362 | /* Power down all displays on reboot, poweroff or halt */ | ||
363 | static void tdo24m_shutdown(struct spi_device *spi) | ||
364 | { | ||
365 | struct tdo24m *lcd = dev_get_drvdata(&spi->dev); | ||
366 | |||
367 | tdo24m_power(lcd, FB_BLANK_POWERDOWN); | ||
368 | } | ||
369 | |||
370 | static struct spi_driver tdo24m_driver = { | ||
371 | .driver = { | ||
372 | .name = "tdo24m", | ||
373 | .owner = THIS_MODULE, | ||
374 | }, | ||
375 | .probe = tdo24m_probe, | ||
376 | .remove = __devexit_p(tdo24m_remove), | ||
377 | .shutdown = tdo24m_shutdown, | ||
378 | .suspend = tdo24m_suspend, | ||
379 | .resume = tdo24m_resume, | ||
380 | }; | ||
381 | |||
382 | static int __init tdo24m_init(void) | ||
383 | { | ||
384 | return spi_register_driver(&tdo24m_driver); | ||
385 | } | ||
386 | module_init(tdo24m_init); | ||
387 | |||
388 | static void __exit tdo24m_exit(void) | ||
389 | { | ||
390 | spi_unregister_driver(&tdo24m_driver); | ||
391 | } | ||
392 | module_exit(tdo24m_exit); | ||
393 | |||
394 | MODULE_AUTHOR("Eric Miao <eric.miao@marvell.com>"); | ||
395 | MODULE_DESCRIPTION("Driver for Toppoly TDO24M LCD Panel"); | ||
396 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/fbmem.c b/drivers/video/fbmem.c index 98843c2ecf73..0737570030f5 100644 --- a/drivers/video/fbmem.c +++ b/drivers/video/fbmem.c | |||
@@ -979,6 +979,7 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var) | |||
979 | 979 | ||
980 | info->flags &= ~FBINFO_MISC_USEREVENT; | 980 | info->flags &= ~FBINFO_MISC_USEREVENT; |
981 | event.info = info; | 981 | event.info = info; |
982 | event.data = &mode; | ||
982 | fb_notifier_call_chain(evnt, &event); | 983 | fb_notifier_call_chain(evnt, &event); |
983 | } | 984 | } |
984 | } | 985 | } |
diff --git a/drivers/video/metronomefb.c b/drivers/video/metronomefb.c index cc4c038a1b3f..afeed0611e3e 100644 --- a/drivers/video/metronomefb.c +++ b/drivers/video/metronomefb.c | |||
@@ -40,29 +40,63 @@ | |||
40 | 40 | ||
41 | #include <asm/unaligned.h> | 41 | #include <asm/unaligned.h> |
42 | 42 | ||
43 | |||
44 | #define DEBUG 1 | ||
45 | #ifdef DEBUG | ||
46 | #define DPRINTK(f, a...) printk(KERN_DEBUG "%s: " f, __func__ , ## a) | ||
47 | #else | ||
48 | #define DPRINTK(f, a...) | ||
49 | #endif | ||
50 | |||
51 | |||
52 | /* Display specific information */ | 43 | /* Display specific information */ |
53 | #define DPY_W 832 | 44 | #define DPY_W 832 |
54 | #define DPY_H 622 | 45 | #define DPY_H 622 |
55 | 46 | ||
47 | static int user_wfm_size; | ||
48 | |||
56 | /* frame differs from image. frame includes non-visible pixels */ | 49 | /* frame differs from image. frame includes non-visible pixels */ |
57 | struct epd_frame { | 50 | struct epd_frame { |
58 | int fw; /* frame width */ | 51 | int fw; /* frame width */ |
59 | int fh; /* frame height */ | 52 | int fh; /* frame height */ |
53 | u16 config[4]; | ||
54 | int wfm_size; | ||
60 | }; | 55 | }; |
61 | 56 | ||
62 | static struct epd_frame epd_frame_table[] = { | 57 | static struct epd_frame epd_frame_table[] = { |
63 | { | 58 | { |
64 | .fw = 832, | 59 | .fw = 832, |
65 | .fh = 622 | 60 | .fh = 622, |
61 | .config = { | ||
62 | 15 /* sdlew */ | ||
63 | | 2 << 8 /* sdosz */ | ||
64 | | 0 << 11 /* sdor */ | ||
65 | | 0 << 12 /* sdces */ | ||
66 | | 0 << 15, /* sdcer */ | ||
67 | 42 /* gdspl */ | ||
68 | | 1 << 8 /* gdr1 */ | ||
69 | | 1 << 9 /* sdshr */ | ||
70 | | 0 << 15, /* gdspp */ | ||
71 | 18 /* gdspw */ | ||
72 | | 0 << 15, /* dispc */ | ||
73 | 599 /* vdlc */ | ||
74 | | 0 << 11 /* dsi */ | ||
75 | | 0 << 12, /* dsic */ | ||
76 | }, | ||
77 | .wfm_size = 47001, | ||
78 | }, | ||
79 | { | ||
80 | .fw = 1088, | ||
81 | .fh = 791, | ||
82 | .config = { | ||
83 | 0x0104, | ||
84 | 0x031f, | ||
85 | 0x0088, | ||
86 | 0x02ff, | ||
87 | }, | ||
88 | .wfm_size = 46770, | ||
89 | }, | ||
90 | { | ||
91 | .fw = 1200, | ||
92 | .fh = 842, | ||
93 | .config = { | ||
94 | 0x0101, | ||
95 | 0x030e, | ||
96 | 0x0012, | ||
97 | 0x0280, | ||
98 | }, | ||
99 | .wfm_size = 46770, | ||
66 | }, | 100 | }, |
67 | }; | 101 | }; |
68 | 102 | ||
@@ -134,9 +168,8 @@ static u16 calc_img_cksum(u16 *start, int length) | |||
134 | } | 168 | } |
135 | 169 | ||
136 | /* here we decode the incoming waveform file and populate metromem */ | 170 | /* here we decode the incoming waveform file and populate metromem */ |
137 | #define EXP_WFORM_SIZE 47001 | 171 | static int __devinit load_waveform(u8 *mem, size_t size, int m, int t, |
138 | static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, | 172 | struct metronomefb_par *par) |
139 | u8 *frame_count) | ||
140 | { | 173 | { |
141 | int tta; | 174 | int tta; |
142 | int wmta; | 175 | int wmta; |
@@ -148,26 +181,31 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, | |||
148 | int wfm_idx, owfm_idx; | 181 | int wfm_idx, owfm_idx; |
149 | int mem_idx = 0; | 182 | int mem_idx = 0; |
150 | struct waveform_hdr *wfm_hdr; | 183 | struct waveform_hdr *wfm_hdr; |
184 | u8 *metromem = par->metromem_wfm; | ||
185 | struct device *dev = par->info->dev; | ||
151 | 186 | ||
152 | if (size != EXP_WFORM_SIZE) { | 187 | if (user_wfm_size) |
153 | printk(KERN_ERR "Error: unexpected size %d != %d\n", size, | 188 | epd_frame_table[par->dt].wfm_size = user_wfm_size; |
154 | EXP_WFORM_SIZE); | 189 | |
190 | if (size != epd_frame_table[par->dt].wfm_size) { | ||
191 | dev_err(dev, "Error: unexpected size %d != %d\n", size, | ||
192 | epd_frame_table[par->dt].wfm_size); | ||
155 | return -EINVAL; | 193 | return -EINVAL; |
156 | } | 194 | } |
157 | 195 | ||
158 | wfm_hdr = (struct waveform_hdr *) mem; | 196 | wfm_hdr = (struct waveform_hdr *) mem; |
159 | 197 | ||
160 | if (wfm_hdr->fvsn != 1) { | 198 | if (wfm_hdr->fvsn != 1) { |
161 | printk(KERN_ERR "Error: bad fvsn %x\n", wfm_hdr->fvsn); | 199 | dev_err(dev, "Error: bad fvsn %x\n", wfm_hdr->fvsn); |
162 | return -EINVAL; | 200 | return -EINVAL; |
163 | } | 201 | } |
164 | if (wfm_hdr->luts != 0) { | 202 | if (wfm_hdr->luts != 0) { |
165 | printk(KERN_ERR "Error: bad luts %x\n", wfm_hdr->luts); | 203 | dev_err(dev, "Error: bad luts %x\n", wfm_hdr->luts); |
166 | return -EINVAL; | 204 | return -EINVAL; |
167 | } | 205 | } |
168 | cksum = calc_cksum(32, 47, mem); | 206 | cksum = calc_cksum(32, 47, mem); |
169 | if (cksum != wfm_hdr->wfm_cs) { | 207 | if (cksum != wfm_hdr->wfm_cs) { |
170 | printk(KERN_ERR "Error: bad cksum %x != %x\n", cksum, | 208 | dev_err(dev, "Error: bad cksum %x != %x\n", cksum, |
171 | wfm_hdr->wfm_cs); | 209 | wfm_hdr->wfm_cs); |
172 | return -EINVAL; | 210 | return -EINVAL; |
173 | } | 211 | } |
@@ -175,7 +213,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, | |||
175 | wfm_hdr->trc += 1; | 213 | wfm_hdr->trc += 1; |
176 | for (i = 0; i < 5; i++) { | 214 | for (i = 0; i < 5; i++) { |
177 | if (*(wfm_hdr->stuff2a + i) != 0) { | 215 | if (*(wfm_hdr->stuff2a + i) != 0) { |
178 | printk(KERN_ERR "Error: unexpected value in padding\n"); | 216 | dev_err(dev, "Error: unexpected value in padding\n"); |
179 | return -EINVAL; | 217 | return -EINVAL; |
180 | } | 218 | } |
181 | } | 219 | } |
@@ -200,7 +238,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, | |||
200 | return -EINVAL; | 238 | return -EINVAL; |
201 | cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem); | 239 | cksum = calc_cksum(sizeof(*wfm_hdr), cksum_idx, mem); |
202 | if (cksum != mem[cksum_idx]) { | 240 | if (cksum != mem[cksum_idx]) { |
203 | printk(KERN_ERR "Error: bad temperature range table cksum" | 241 | dev_err(dev, "Error: bad temperature range table cksum" |
204 | " %x != %x\n", cksum, mem[cksum_idx]); | 242 | " %x != %x\n", cksum, mem[cksum_idx]); |
205 | return -EINVAL; | 243 | return -EINVAL; |
206 | } | 244 | } |
@@ -212,7 +250,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, | |||
212 | return -EINVAL; | 250 | return -EINVAL; |
213 | cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); | 251 | cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); |
214 | if (cksum != mem[cksum_idx]) { | 252 | if (cksum != mem[cksum_idx]) { |
215 | printk(KERN_ERR "Error: bad mode table address cksum" | 253 | dev_err(dev, "Error: bad mode table address cksum" |
216 | " %x != %x\n", cksum, mem[cksum_idx]); | 254 | " %x != %x\n", cksum, mem[cksum_idx]); |
217 | return -EINVAL; | 255 | return -EINVAL; |
218 | } | 256 | } |
@@ -224,7 +262,7 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, | |||
224 | return -EINVAL; | 262 | return -EINVAL; |
225 | cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); | 263 | cksum = calc_cksum(cksum_idx - 3, cksum_idx, mem); |
226 | if (cksum != mem[cksum_idx]) { | 264 | if (cksum != mem[cksum_idx]) { |
227 | printk(KERN_ERR "Error: bad temperature table address cksum" | 265 | dev_err(dev, "Error: bad temperature table address cksum" |
228 | " %x != %x\n", cksum, mem[cksum_idx]); | 266 | " %x != %x\n", cksum, mem[cksum_idx]); |
229 | return -EINVAL; | 267 | return -EINVAL; |
230 | } | 268 | } |
@@ -259,11 +297,11 @@ static int load_waveform(u8 *mem, size_t size, u8 *metromem, int m, int t, | |||
259 | return -EINVAL; | 297 | return -EINVAL; |
260 | cksum = calc_cksum(owfm_idx, cksum_idx, mem); | 298 | cksum = calc_cksum(owfm_idx, cksum_idx, mem); |
261 | if (cksum != mem[cksum_idx]) { | 299 | if (cksum != mem[cksum_idx]) { |
262 | printk(KERN_ERR "Error: bad waveform data cksum" | 300 | dev_err(dev, "Error: bad waveform data cksum" |
263 | " %x != %x\n", cksum, mem[cksum_idx]); | 301 | " %x != %x\n", cksum, mem[cksum_idx]); |
264 | return -EINVAL; | 302 | return -EINVAL; |
265 | } | 303 | } |
266 | *frame_count = (mem_idx/64); | 304 | par->frame_count = (mem_idx/64); |
267 | 305 | ||
268 | return 0; | 306 | return 0; |
269 | } | 307 | } |
@@ -274,15 +312,12 @@ static int metronome_display_cmd(struct metronomefb_par *par) | |||
274 | u16 cs; | 312 | u16 cs; |
275 | u16 opcode; | 313 | u16 opcode; |
276 | static u8 borderval; | 314 | static u8 borderval; |
277 | u8 *ptr; | ||
278 | 315 | ||
279 | /* setup display command | 316 | /* setup display command |
280 | we can't immediately set the opcode since the controller | 317 | we can't immediately set the opcode since the controller |
281 | will try parse the command before we've set it all up | 318 | will try parse the command before we've set it all up |
282 | so we just set cs here and set the opcode at the end */ | 319 | so we just set cs here and set the opcode at the end */ |
283 | 320 | ||
284 | ptr = par->metromem; | ||
285 | |||
286 | if (par->metromem_cmd->opcode == 0xCC40) | 321 | if (par->metromem_cmd->opcode == 0xCC40) |
287 | opcode = cs = 0xCC41; | 322 | opcode = cs = 0xCC41; |
288 | else | 323 | else |
@@ -335,44 +370,17 @@ static int __devinit metronome_powerup_cmd(struct metronomefb_par *par) | |||
335 | 370 | ||
336 | static int __devinit metronome_config_cmd(struct metronomefb_par *par) | 371 | static int __devinit metronome_config_cmd(struct metronomefb_par *par) |
337 | { | 372 | { |
338 | int i; | ||
339 | u16 cs; | ||
340 | |||
341 | /* setup config command | 373 | /* setup config command |
342 | we can't immediately set the opcode since the controller | 374 | we can't immediately set the opcode since the controller |
343 | will try parse the command before we've set it all up | 375 | will try parse the command before we've set it all up */ |
344 | so we just set cs here and set the opcode at the end */ | ||
345 | |||
346 | cs = 0xCC10; | ||
347 | |||
348 | /* set the 12 args ( 8 bytes ) for config. see spec for meanings */ | ||
349 | i = 0; | ||
350 | par->metromem_cmd->args[i] = 15 /* sdlew */ | ||
351 | | 2 << 8 /* sdosz */ | ||
352 | | 0 << 11 /* sdor */ | ||
353 | | 0 << 12 /* sdces */ | ||
354 | | 0 << 15; /* sdcer */ | ||
355 | cs += par->metromem_cmd->args[i++]; | ||
356 | |||
357 | par->metromem_cmd->args[i] = 42 /* gdspl */ | ||
358 | | 1 << 8 /* gdr1 */ | ||
359 | | 1 << 9 /* sdshr */ | ||
360 | | 0 << 15; /* gdspp */ | ||
361 | cs += par->metromem_cmd->args[i++]; | ||
362 | |||
363 | par->metromem_cmd->args[i] = 18 /* gdspw */ | ||
364 | | 0 << 15; /* dispc */ | ||
365 | cs += par->metromem_cmd->args[i++]; | ||
366 | |||
367 | par->metromem_cmd->args[i] = 599 /* vdlc */ | ||
368 | | 0 << 11 /* dsi */ | ||
369 | | 0 << 12; /* dsic */ | ||
370 | cs += par->metromem_cmd->args[i++]; | ||
371 | 376 | ||
377 | memcpy(par->metromem_cmd->args, epd_frame_table[par->dt].config, | ||
378 | sizeof(epd_frame_table[par->dt].config)); | ||
372 | /* the rest are 0 */ | 379 | /* the rest are 0 */ |
373 | memset((u8 *) (par->metromem_cmd->args + i), 0, (32-i)*2); | 380 | memset((u8 *) (par->metromem_cmd->args + 4), 0, (32-4)*2); |
374 | 381 | ||
375 | par->metromem_cmd->csum = cs; | 382 | par->metromem_cmd->csum = 0xCC10; |
383 | par->metromem_cmd->csum += calc_img_cksum(par->metromem_cmd->args, 4); | ||
376 | par->metromem_cmd->opcode = 0xCC10; /* config cmd */ | 384 | par->metromem_cmd->opcode = 0xCC10; /* config cmd */ |
377 | 385 | ||
378 | return par->board->met_wait_event(par); | 386 | return par->board->met_wait_event(par); |
@@ -408,12 +416,9 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par) | |||
408 | { | 416 | { |
409 | int res; | 417 | int res; |
410 | 418 | ||
411 | par->board->init_gpio_regs(par); | 419 | res = par->board->setup_io(par); |
412 | 420 | if (res) | |
413 | par->board->init_lcdc_regs(par); | 421 | return res; |
414 | |||
415 | /* now that lcd is setup, setup dma descriptor */ | ||
416 | par->board->post_dma_setup(par); | ||
417 | 422 | ||
418 | res = metronome_powerup_cmd(par); | 423 | res = metronome_powerup_cmd(par); |
419 | if (res) | 424 | if (res) |
@@ -430,16 +435,16 @@ static int __devinit metronome_init_regs(struct metronomefb_par *par) | |||
430 | 435 | ||
431 | static void metronomefb_dpy_update(struct metronomefb_par *par) | 436 | static void metronomefb_dpy_update(struct metronomefb_par *par) |
432 | { | 437 | { |
438 | int fbsize; | ||
433 | u16 cksum; | 439 | u16 cksum; |
434 | unsigned char *buf = (unsigned char __force *)par->info->screen_base; | 440 | unsigned char *buf = (unsigned char __force *)par->info->screen_base; |
435 | 441 | ||
442 | fbsize = par->info->fix.smem_len; | ||
436 | /* copy from vm to metromem */ | 443 | /* copy from vm to metromem */ |
437 | memcpy(par->metromem_img, buf, DPY_W*DPY_H); | 444 | memcpy(par->metromem_img, buf, fbsize); |
438 | 445 | ||
439 | cksum = calc_img_cksum((u16 *) par->metromem_img, | 446 | cksum = calc_img_cksum((u16 *) par->metromem_img, fbsize/2); |
440 | (epd_frame_table[0].fw * DPY_H)/2); | 447 | *((u16 *)(par->metromem_img) + fbsize/2) = cksum; |
441 | *((u16 *)(par->metromem_img) + | ||
442 | (epd_frame_table[0].fw * DPY_H)/2) = cksum; | ||
443 | metronome_display_cmd(par); | 448 | metronome_display_cmd(par); |
444 | } | 449 | } |
445 | 450 | ||
@@ -574,8 +579,10 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
574 | unsigned char *videomemory; | 579 | unsigned char *videomemory; |
575 | struct metronomefb_par *par; | 580 | struct metronomefb_par *par; |
576 | const struct firmware *fw_entry; | 581 | const struct firmware *fw_entry; |
577 | int cmd_size, wfm_size, img_size, padding_size, totalsize; | ||
578 | int i; | 582 | int i; |
583 | int panel_type; | ||
584 | int fw, fh; | ||
585 | int epd_dt_index; | ||
579 | 586 | ||
580 | /* pick up board specific routines */ | 587 | /* pick up board specific routines */ |
581 | board = dev->dev.platform_data; | 588 | board = dev->dev.platform_data; |
@@ -586,96 +593,108 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
586 | if (!try_module_get(board->owner)) | 593 | if (!try_module_get(board->owner)) |
587 | return -ENODEV; | 594 | return -ENODEV; |
588 | 595 | ||
596 | info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev); | ||
597 | if (!info) | ||
598 | goto err; | ||
599 | |||
589 | /* we have two blocks of memory. | 600 | /* we have two blocks of memory. |
590 | info->screen_base which is vm, and is the fb used by apps. | 601 | info->screen_base which is vm, and is the fb used by apps. |
591 | par->metromem which is physically contiguous memory and | 602 | par->metromem which is physically contiguous memory and |
592 | contains the display controller commands, waveform, | 603 | contains the display controller commands, waveform, |
593 | processed image data and padding. this is the data pulled | 604 | processed image data and padding. this is the data pulled |
594 | by the device's LCD controller and pushed to Metronome */ | 605 | by the device's LCD controller and pushed to Metronome. |
606 | the metromem memory is allocated by the board driver and | ||
607 | is provided to us */ | ||
608 | |||
609 | panel_type = board->get_panel_type(); | ||
610 | switch (panel_type) { | ||
611 | case 6: | ||
612 | epd_dt_index = 0; | ||
613 | break; | ||
614 | case 8: | ||
615 | epd_dt_index = 1; | ||
616 | break; | ||
617 | case 97: | ||
618 | epd_dt_index = 2; | ||
619 | break; | ||
620 | default: | ||
621 | dev_err(&dev->dev, "Unexpected panel type. Defaulting to 6\n"); | ||
622 | epd_dt_index = 0; | ||
623 | break; | ||
624 | } | ||
625 | |||
626 | fw = epd_frame_table[epd_dt_index].fw; | ||
627 | fh = epd_frame_table[epd_dt_index].fh; | ||
595 | 628 | ||
596 | videomemorysize = (DPY_W*DPY_H); | 629 | /* we need to add a spare page because our csum caching scheme walks |
630 | * to the end of the page */ | ||
631 | videomemorysize = PAGE_SIZE + (fw * fh); | ||
597 | videomemory = vmalloc(videomemorysize); | 632 | videomemory = vmalloc(videomemorysize); |
598 | if (!videomemory) | 633 | if (!videomemory) |
599 | return -ENOMEM; | 634 | goto err_fb_rel; |
600 | 635 | ||
601 | memset(videomemory, 0, videomemorysize); | 636 | memset(videomemory, 0, videomemorysize); |
602 | 637 | ||
603 | info = framebuffer_alloc(sizeof(struct metronomefb_par), &dev->dev); | ||
604 | if (!info) | ||
605 | goto err_vfree; | ||
606 | |||
607 | info->screen_base = (char __force __iomem *)videomemory; | 638 | info->screen_base = (char __force __iomem *)videomemory; |
608 | info->fbops = &metronomefb_ops; | 639 | info->fbops = &metronomefb_ops; |
609 | 640 | ||
641 | metronomefb_fix.line_length = fw; | ||
642 | metronomefb_var.xres = fw; | ||
643 | metronomefb_var.yres = fh; | ||
644 | metronomefb_var.xres_virtual = fw; | ||
645 | metronomefb_var.yres_virtual = fh; | ||
610 | info->var = metronomefb_var; | 646 | info->var = metronomefb_var; |
611 | info->fix = metronomefb_fix; | 647 | info->fix = metronomefb_fix; |
612 | info->fix.smem_len = videomemorysize; | 648 | info->fix.smem_len = videomemorysize; |
613 | par = info->par; | 649 | par = info->par; |
614 | par->info = info; | 650 | par->info = info; |
615 | par->board = board; | 651 | par->board = board; |
652 | par->dt = epd_dt_index; | ||
616 | init_waitqueue_head(&par->waitq); | 653 | init_waitqueue_head(&par->waitq); |
617 | 654 | ||
618 | /* this table caches per page csum values. */ | 655 | /* this table caches per page csum values. */ |
619 | par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); | 656 | par->csum_table = vmalloc(videomemorysize/PAGE_SIZE); |
620 | if (!par->csum_table) | 657 | if (!par->csum_table) |
658 | goto err_vfree; | ||
659 | |||
660 | /* the physical framebuffer that we use is setup by | ||
661 | * the platform device driver. It will provide us | ||
662 | * with cmd, wfm and image memory in a contiguous area. */ | ||
663 | retval = board->setup_fb(par); | ||
664 | if (retval) { | ||
665 | dev_err(&dev->dev, "Failed to setup fb\n"); | ||
621 | goto err_csum_table; | 666 | goto err_csum_table; |
667 | } | ||
622 | 668 | ||
623 | /* the metromem buffer is divided as follows: | 669 | /* after this point we should have a framebuffer */ |
624 | command | CRC | padding | 670 | if ((!par->metromem_wfm) || (!par->metromem_img) || |
625 | 16kb waveform data | CRC | padding | 671 | (!par->metromem_dma)) { |
626 | image data | CRC | 672 | dev_err(&dev->dev, "fb access failure\n"); |
627 | and an extra 256 bytes for dma descriptors | 673 | retval = -EINVAL; |
628 | eg: IW=832 IH=622 WS=128 | 674 | goto err_csum_table; |
629 | */ | ||
630 | |||
631 | cmd_size = 1 * epd_frame_table[0].fw; | ||
632 | wfm_size = ((16*1024 + 2 + epd_frame_table[0].fw - 1) | ||
633 | / epd_frame_table[0].fw) * epd_frame_table[0].fw; | ||
634 | img_size = epd_frame_table[0].fh * epd_frame_table[0].fw; | ||
635 | padding_size = 4 * epd_frame_table[0].fw; | ||
636 | totalsize = cmd_size + wfm_size + img_size + padding_size; | ||
637 | par->metromemsize = PAGE_ALIGN(totalsize + 256); | ||
638 | DPRINTK("desired memory size = %d\n", par->metromemsize); | ||
639 | dev->dev.coherent_dma_mask = 0xffffffffull; | ||
640 | par->metromem = dma_alloc_writecombine(&dev->dev, par->metromemsize, | ||
641 | &par->metromem_dma, GFP_KERNEL); | ||
642 | if (!par->metromem) { | ||
643 | printk(KERN_ERR | ||
644 | "metronomefb: unable to allocate dma buffer\n"); | ||
645 | goto err_vfree; | ||
646 | } | 675 | } |
647 | 676 | ||
648 | info->fix.smem_start = par->metromem_dma; | 677 | info->fix.smem_start = par->metromem_dma; |
649 | par->metromem_cmd = (struct metromem_cmd *) par->metromem; | ||
650 | par->metromem_wfm = par->metromem + cmd_size; | ||
651 | par->metromem_img = par->metromem + cmd_size + wfm_size; | ||
652 | par->metromem_img_csum = (u16 *) (par->metromem_img + | ||
653 | (epd_frame_table[0].fw * DPY_H)); | ||
654 | DPRINTK("img offset=0x%x\n", cmd_size + wfm_size); | ||
655 | par->metromem_desc = (struct metromem_desc *) (par->metromem + cmd_size | ||
656 | + wfm_size + img_size + padding_size); | ||
657 | par->metromem_desc_dma = par->metromem_dma + cmd_size + wfm_size | ||
658 | + img_size + padding_size; | ||
659 | 678 | ||
660 | /* load the waveform in. assume mode 3, temp 31 for now | 679 | /* load the waveform in. assume mode 3, temp 31 for now |
661 | a) request the waveform file from userspace | 680 | a) request the waveform file from userspace |
662 | b) process waveform and decode into metromem */ | 681 | b) process waveform and decode into metromem */ |
663 | retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); | 682 | retval = request_firmware(&fw_entry, "metronome.wbf", &dev->dev); |
664 | if (retval < 0) { | 683 | if (retval < 0) { |
665 | printk(KERN_ERR "metronomefb: couldn't get waveform\n"); | 684 | dev_err(&dev->dev, "Failed to get waveform\n"); |
666 | goto err_dma_free; | 685 | goto err_csum_table; |
667 | } | 686 | } |
668 | 687 | ||
669 | retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, | 688 | retval = load_waveform((u8 *) fw_entry->data, fw_entry->size, 3, 31, |
670 | par->metromem_wfm, 3, 31, &par->frame_count); | 689 | par); |
671 | release_firmware(fw_entry); | 690 | release_firmware(fw_entry); |
672 | if (retval < 0) { | 691 | if (retval < 0) { |
673 | printk(KERN_ERR "metronomefb: couldn't process waveform\n"); | 692 | dev_err(&dev->dev, "Failed processing waveform\n"); |
674 | goto err_dma_free; | 693 | goto err_csum_table; |
675 | } | 694 | } |
676 | 695 | ||
677 | if (board->setup_irq(info)) | 696 | if (board->setup_irq(info)) |
678 | goto err_dma_free; | 697 | goto err_csum_table; |
679 | 698 | ||
680 | retval = metronome_init_regs(par); | 699 | retval = metronome_init_regs(par); |
681 | if (retval < 0) | 700 | if (retval < 0) |
@@ -688,8 +707,8 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
688 | 707 | ||
689 | retval = fb_alloc_cmap(&info->cmap, 8, 0); | 708 | retval = fb_alloc_cmap(&info->cmap, 8, 0); |
690 | if (retval < 0) { | 709 | if (retval < 0) { |
691 | printk(KERN_ERR "Failed to allocate colormap\n"); | 710 | dev_err(&dev->dev, "Failed to allocate colormap\n"); |
692 | goto err_fb_rel; | 711 | goto err_free_irq; |
693 | } | 712 | } |
694 | 713 | ||
695 | /* set cmap */ | 714 | /* set cmap */ |
@@ -704,7 +723,7 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
704 | 723 | ||
705 | platform_set_drvdata(dev, info); | 724 | platform_set_drvdata(dev, info); |
706 | 725 | ||
707 | printk(KERN_INFO | 726 | dev_dbg(&dev->dev, |
708 | "fb%d: Metronome frame buffer device, using %dK of video" | 727 | "fb%d: Metronome frame buffer device, using %dK of video" |
709 | " memory\n", info->node, videomemorysize >> 10); | 728 | " memory\n", info->node, videomemorysize >> 10); |
710 | 729 | ||
@@ -712,17 +731,15 @@ static int __devinit metronomefb_probe(struct platform_device *dev) | |||
712 | 731 | ||
713 | err_cmap: | 732 | err_cmap: |
714 | fb_dealloc_cmap(&info->cmap); | 733 | fb_dealloc_cmap(&info->cmap); |
715 | err_fb_rel: | ||
716 | framebuffer_release(info); | ||
717 | err_free_irq: | 734 | err_free_irq: |
718 | board->free_irq(info); | 735 | board->cleanup(par); |
719 | err_dma_free: | ||
720 | dma_free_writecombine(&dev->dev, par->metromemsize, par->metromem, | ||
721 | par->metromem_dma); | ||
722 | err_csum_table: | 736 | err_csum_table: |
723 | vfree(par->csum_table); | 737 | vfree(par->csum_table); |
724 | err_vfree: | 738 | err_vfree: |
725 | vfree(videomemory); | 739 | vfree(videomemory); |
740 | err_fb_rel: | ||
741 | framebuffer_release(info); | ||
742 | err: | ||
726 | module_put(board->owner); | 743 | module_put(board->owner); |
727 | return retval; | 744 | return retval; |
728 | } | 745 | } |
@@ -733,15 +750,15 @@ static int __devexit metronomefb_remove(struct platform_device *dev) | |||
733 | 750 | ||
734 | if (info) { | 751 | if (info) { |
735 | struct metronomefb_par *par = info->par; | 752 | struct metronomefb_par *par = info->par; |
753 | |||
754 | unregister_framebuffer(info); | ||
736 | fb_deferred_io_cleanup(info); | 755 | fb_deferred_io_cleanup(info); |
737 | dma_free_writecombine(&dev->dev, par->metromemsize, | ||
738 | par->metromem, par->metromem_dma); | ||
739 | fb_dealloc_cmap(&info->cmap); | 756 | fb_dealloc_cmap(&info->cmap); |
757 | par->board->cleanup(par); | ||
740 | vfree(par->csum_table); | 758 | vfree(par->csum_table); |
741 | unregister_framebuffer(info); | ||
742 | vfree((void __force *)info->screen_base); | 759 | vfree((void __force *)info->screen_base); |
743 | par->board->free_irq(info); | ||
744 | module_put(par->board->owner); | 760 | module_put(par->board->owner); |
761 | dev_dbg(&dev->dev, "calling release\n"); | ||
745 | framebuffer_release(info); | 762 | framebuffer_release(info); |
746 | } | 763 | } |
747 | return 0; | 764 | return 0; |
@@ -766,6 +783,9 @@ static void __exit metronomefb_exit(void) | |||
766 | platform_driver_unregister(&metronomefb_driver); | 783 | platform_driver_unregister(&metronomefb_driver); |
767 | } | 784 | } |
768 | 785 | ||
786 | module_param(user_wfm_size, uint, 0); | ||
787 | MODULE_PARM_DESC(user_wfm_size, "Set custom waveform size"); | ||
788 | |||
769 | module_init(metronomefb_init); | 789 | module_init(metronomefb_init); |
770 | module_exit(metronomefb_exit); | 790 | module_exit(metronomefb_exit); |
771 | 791 | ||