aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/mach-pxa
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-pxa')
-rw-r--r--arch/arm/mach-pxa/Makefile1
-rw-r--r--arch/arm/mach-pxa/akita-ioexp.c223
2 files changed, 224 insertions, 0 deletions
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index c83092e298a7..32526a0a6f86 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MACH_MAINSTONE) += mainstone.o
13obj-$(CONFIG_ARCH_PXA_IDP) += idp.o 13obj-$(CONFIG_ARCH_PXA_IDP) += idp.o
14obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o corgi_pm.o 14obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o corgi_pm.o
15obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o 15obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o
16obj-$(CONFIG_MACH_AKITA) += akita-ioexp.o
16obj-$(CONFIG_MACH_POODLE) += poodle.o 17obj-$(CONFIG_MACH_POODLE) += poodle.o
17obj-$(CONFIG_MACH_TOSA) += tosa.o 18obj-$(CONFIG_MACH_TOSA) += tosa.o
18 19
diff --git a/arch/arm/mach-pxa/akita-ioexp.c b/arch/arm/mach-pxa/akita-ioexp.c
new file mode 100644
index 000000000000..f6d73cc01f78
--- /dev/null
+++ b/arch/arm/mach-pxa/akita-ioexp.c
@@ -0,0 +1,223 @@
1/*
2 * Support for the Extra GPIOs on the Sharp SL-C1000 (Akita)
3 * (uses a Maxim MAX7310 8 Port IO Expander)
4 *
5 * Copyright 2005 Openedhand Ltd.
6 *
7 * Author: Richard Purdie <richard@openedhand.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/kernel.h>
16#include <linux/init.h>
17#include <linux/platform_device.h>
18#include <linux/module.h>
19#include <linux/i2c.h>
20#include <linux/slab.h>
21#include <linux/workqueue.h>
22#include <asm/arch/akita.h>
23
24/* MAX7310 Regiser Map */
25#define MAX7310_INPUT 0x00
26#define MAX7310_OUTPUT 0x01
27#define MAX7310_POLINV 0x02
28#define MAX7310_IODIR 0x03 /* 1 = Input, 0 = Output */
29#define MAX7310_TIMEOUT 0x04
30
31/* Addresses to scan */
32static unsigned short normal_i2c[] = { 0x18, I2C_CLIENT_END };
33
34/* I2C Magic */
35I2C_CLIENT_INSMOD;
36
37static int max7310_write(struct i2c_client *client, int address, int data);
38static struct i2c_client max7310_template;
39static void akita_ioexp_work(void *private_);
40
41static struct device *akita_ioexp_device;
42static unsigned char ioexp_output_value = AKITA_IOEXP_IO_OUT;
43DECLARE_WORK(akita_ioexp, akita_ioexp_work, NULL);
44
45
46/*
47 * MAX7310 Access
48 */
49static int max7310_config(struct device *dev, int iomode, int polarity)
50{
51 int ret;
52 struct i2c_client *client = to_i2c_client(dev);
53
54 ret = max7310_write(client, MAX7310_POLINV, polarity);
55 if (ret < 0)
56 return ret;
57 ret = max7310_write(client, MAX7310_IODIR, iomode);
58 return ret;
59}
60
61static int max7310_set_ouputs(struct device *dev, int outputs)
62{
63 struct i2c_client *client = to_i2c_client(dev);
64
65 return max7310_write(client, MAX7310_OUTPUT, outputs);
66}
67
68/*
69 * I2C Functions
70 */
71static int max7310_write(struct i2c_client *client, int address, int value)
72{
73 u8 data[2];
74
75 data[0] = address & 0xff;
76 data[1] = value & 0xff;
77
78 if (i2c_master_send(client, data, 2) == 2)
79 return 0;
80 return -1;
81}
82
83static int max7310_detect(struct i2c_adapter *adapter, int address, int kind)
84{
85 struct i2c_client *new_client;
86 int err;
87
88 if (!(new_client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL)))
89 return -ENOMEM;
90
91 max7310_template.adapter = adapter;
92 max7310_template.addr = address;
93
94 memcpy(new_client, &max7310_template, sizeof(struct i2c_client));
95
96 if ((err = i2c_attach_client(new_client))) {
97 kfree(new_client);
98 return err;
99 }
100
101 max7310_config(&new_client->dev, AKITA_IOEXP_IO_DIR, 0);
102 akita_ioexp_device = &new_client->dev;
103 schedule_work(&akita_ioexp);
104
105 return 0;
106}
107
108static int max7310_attach_adapter(struct i2c_adapter *adapter)
109{
110 return i2c_probe(adapter, &addr_data, max7310_detect);
111}
112
113static int max7310_detach_client(struct i2c_client *client)
114{
115 int err;
116
117 akita_ioexp_device = NULL;
118
119 if ((err = i2c_detach_client(client)))
120 return err;
121
122 kfree(client);
123 return 0;
124}
125
126static struct i2c_driver max7310_i2c_driver = {
127 .owner = THIS_MODULE,
128 .name = "akita-max7310",
129 .id = I2C_DRIVERID_AKITAIOEXP,
130 .flags = I2C_DF_NOTIFY,
131 .attach_adapter = max7310_attach_adapter,
132 .detach_client = max7310_detach_client,
133};
134
135static struct i2c_client max7310_template = {
136 name: "akita-max7310",
137 flags: I2C_CLIENT_ALLOW_USE,
138 driver: &max7310_i2c_driver,
139};
140
141void akita_set_ioexp(struct device *dev, unsigned char bit)
142{
143 ioexp_output_value |= bit;
144
145 if (akita_ioexp_device)
146 schedule_work(&akita_ioexp);
147 return;
148}
149
150void akita_reset_ioexp(struct device *dev, unsigned char bit)
151{
152 ioexp_output_value &= ~bit;
153
154 if (akita_ioexp_device)
155 schedule_work(&akita_ioexp);
156 return;
157}
158
159EXPORT_SYMBOL(akita_set_ioexp);
160EXPORT_SYMBOL(akita_reset_ioexp);
161
162static void akita_ioexp_work(void *private_)
163{
164 if (akita_ioexp_device)
165 max7310_set_ouputs(akita_ioexp_device, ioexp_output_value);
166}
167
168
169#ifdef CONFIG_PM
170static int akita_ioexp_suspend(struct platform_device *pdev, pm_message_t state)
171{
172 flush_scheduled_work();
173 return 0;
174}
175
176static int akita_ioexp_resume(struct platform_device *pdev)
177{
178 schedule_work(&akita_ioexp);
179 return 0;
180}
181#else
182#define akita_ioexp_suspend NULL
183#define akita_ioexp_resume NULL
184#endif
185
186static int __init akita_ioexp_probe(struct platform_device *pdev)
187{
188 return i2c_add_driver(&max7310_i2c_driver);
189}
190
191static int akita_ioexp_remove(struct platform_device *pdev)
192{
193 i2c_del_driver(&max7310_i2c_driver);
194 return 0;
195}
196
197static struct platform_driver akita_ioexp_driver = {
198 .probe = akita_ioexp_probe,
199 .remove = akita_ioexp_remove,
200 .suspend = akita_ioexp_suspend,
201 .resume = akita_ioexp_resume,
202 .driver = {
203 .name = "akita-ioexp",
204 },
205};
206
207static int __init akita_ioexp_init(void)
208{
209 return platform_driver_register(&akita_ioexp_driver);
210}
211
212static void __exit akita_ioexp_exit(void)
213{
214 platform_driver_unregister(&akita_ioexp_driver);
215}
216
217MODULE_AUTHOR("Richard Purdie <rpurdie@openedhand.com>");
218MODULE_DESCRIPTION("Akita IO-Expander driver");
219MODULE_LICENSE("GPL");
220
221fs_initcall(akita_ioexp_init);
222module_exit(akita_ioexp_exit);
223