aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorBart Van Assche <bart.vanassche@gmail.com>2008-01-27 12:14:45 -0500
committerJean Delvare <khali@hyperion.delvare>2008-01-27 12:14:45 -0500
commit5864ae03ca982fb60bedeebfd67562db37c1ee6a (patch)
treea2c0982c544be712246e797451abb7bf850492e7 /drivers
parent217bcec4425cdc8fb90ce688eb4d5b5140713046 (diff)
i2c: Add support for the PCF8575 chip
Signed-off-by: Bart Van Assche <bart.vanassche@gmail.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/i2c/chips/Kconfig16
-rw-r--r--drivers/i2c/chips/Makefile1
-rw-r--r--drivers/i2c/chips/pcf8575.c214
3 files changed, 230 insertions, 1 deletions
diff --git a/drivers/i2c/chips/Kconfig b/drivers/i2c/chips/Kconfig
index 2e1c24f671cf..17702b32eab0 100644
--- a/drivers/i2c/chips/Kconfig
+++ b/drivers/i2c/chips/Kconfig
@@ -57,7 +57,7 @@ config SENSORS_PCF8574
57 default n 57 default n
58 help 58 help
59 If you say yes here you get support for Philips PCF8574 and 59 If you say yes here you get support for Philips PCF8574 and
60 PCF8574A chips. 60 PCF8574A chips. These chips are 8-bit I/O expanders for the I2C bus.
61 61
62 This driver can also be built as a module. If so, the module 62 This driver can also be built as a module. If so, the module
63 will be called pcf8574. 63 will be called pcf8574.
@@ -65,6 +65,20 @@ config SENSORS_PCF8574
65 These devices are hard to detect and rarely found on mainstream 65 These devices are hard to detect and rarely found on mainstream
66 hardware. If unsure, say N. 66 hardware. If unsure, say N.
67 67
68config PCF8575
69 tristate "Philips PCF8575"
70 default n
71 help
72 If you say yes here you get support for Philips PCF8575 chip.
73 This chip is a 16-bit I/O expander for the I2C bus. Several other
74 chip manufacturers sell equivalent chips, e.g. Texas Instruments.
75
76 This driver can also be built as a module. If so, the module
77 will be called pcf8575.
78
79 This device is hard to detect and is rarely found on mainstream
80 hardware. If unsure, say N.
81
68config SENSORS_PCA9539 82config SENSORS_PCA9539
69 tristate "Philips PCA9539 16-bit I/O port" 83 tristate "Philips PCA9539 16-bit I/O port"
70 depends on EXPERIMENTAL 84 depends on EXPERIMENTAL
diff --git a/drivers/i2c/chips/Makefile b/drivers/i2c/chips/Makefile
index ca924e105959..50d4734b5038 100644
--- a/drivers/i2c/chips/Makefile
+++ b/drivers/i2c/chips/Makefile
@@ -10,6 +10,7 @@ obj-$(CONFIG_SENSORS_MAX6875) += max6875.o
10obj-$(CONFIG_SENSORS_M41T00) += m41t00.o 10obj-$(CONFIG_SENSORS_M41T00) += m41t00.o
11obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o 11obj-$(CONFIG_SENSORS_PCA9539) += pca9539.o
12obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o 12obj-$(CONFIG_SENSORS_PCF8574) += pcf8574.o
13obj-$(CONFIG_PCF8575) += pcf8575.o
13obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o 14obj-$(CONFIG_SENSORS_PCF8591) += pcf8591.o
14obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o 15obj-$(CONFIG_ISP1301_OMAP) += isp1301_omap.o
15obj-$(CONFIG_TPS65010) += tps65010.o 16obj-$(CONFIG_TPS65010) += tps65010.o
diff --git a/drivers/i2c/chips/pcf8575.c b/drivers/i2c/chips/pcf8575.c
new file mode 100644
index 000000000000..db3c87726978
--- /dev/null
+++ b/drivers/i2c/chips/pcf8575.c
@@ -0,0 +1,214 @@
1/*
2 pcf8575.c
3
4 About the PCF8575 chip: the PCF8575 is a 16-bit I/O expander for the I2C bus
5 produced by a.o. Philips Semiconductors.
6
7 Copyright (C) 2006 Michael Hennerich, Analog Devices Inc.
8 <hennerich@blackfin.uclinux.org>
9 Based on pcf8574.c.
10
11 Copyright (c) 2007 Bart Van Assche <bart.vanassche@gmail.com>.
12 Ported this driver from ucLinux to the mainstream Linux kernel.
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 as published by
16 the Free Software Foundation; either version 2 of the License, or
17 (at your option) any later version.
18
19 This program is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 GNU General Public License for more details.
23
24 You should have received a copy of the GNU General Public License
25 along with this program; if not, write to the Free Software
26 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
27*/
28
29#include <linux/module.h>
30#include <linux/init.h>
31#include <linux/i2c.h>
32#include <linux/slab.h> /* kzalloc() */
33#include <linux/sysfs.h> /* sysfs_create_group() */
34
35/* Addresses to scan */
36static unsigned short normal_i2c[] = {
37 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
38 I2C_CLIENT_END
39};
40
41/* Insmod parameters */
42I2C_CLIENT_INSMOD;
43
44
45/* Each client has this additional data */
46struct pcf8575_data {
47 struct i2c_client client;
48 int write; /* last written value, or error code */
49};
50
51static int pcf8575_attach_adapter(struct i2c_adapter *adapter);
52static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind);
53static int pcf8575_detach_client(struct i2c_client *client);
54
55/* This is the driver that will be inserted */
56static struct i2c_driver pcf8575_driver = {
57 .driver = {
58 .owner = THIS_MODULE,
59 .name = "pcf8575",
60 },
61 .attach_adapter = pcf8575_attach_adapter,
62 .detach_client = pcf8575_detach_client,
63};
64
65/* following are the sysfs callback functions */
66static ssize_t show_read(struct device *dev, struct device_attribute *attr,
67 char *buf)
68{
69 struct i2c_client *client = to_i2c_client(dev);
70 u16 val;
71 u8 iopin_state[2];
72
73 i2c_master_recv(client, iopin_state, 2);
74
75 val = iopin_state[0];
76 val |= iopin_state[1] << 8;
77
78 return sprintf(buf, "%u\n", val);
79}
80
81static DEVICE_ATTR(read, S_IRUGO, show_read, NULL);
82
83static ssize_t show_write(struct device *dev, struct device_attribute *attr,
84 char *buf)
85{
86 struct pcf8575_data *data = dev_get_drvdata(dev);
87 if (data->write < 0)
88 return data->write;
89 return sprintf(buf, "%d\n", data->write);
90}
91
92static ssize_t set_write(struct device *dev, struct device_attribute *attr,
93 const char *buf, size_t count)
94{
95 struct i2c_client *client = to_i2c_client(dev);
96 struct pcf8575_data *data = i2c_get_clientdata(client);
97 unsigned long val = simple_strtoul(buf, NULL, 10);
98 u8 iopin_state[2];
99
100 if (val > 0xffff)
101 return -EINVAL;
102
103 data->write = val;
104
105 iopin_state[0] = val & 0xFF;
106 iopin_state[1] = val >> 8;
107
108 i2c_master_send(client, iopin_state, 2);
109
110 return count;
111}
112
113static DEVICE_ATTR(write, S_IWUSR | S_IRUGO, show_write, set_write);
114
115static struct attribute *pcf8575_attributes[] = {
116 &dev_attr_read.attr,
117 &dev_attr_write.attr,
118 NULL
119};
120
121static const struct attribute_group pcf8575_attr_group = {
122 .attrs = pcf8575_attributes,
123};
124
125/*
126 * Real code
127 */
128
129static int pcf8575_attach_adapter(struct i2c_adapter *adapter)
130{
131 return i2c_probe(adapter, &addr_data, pcf8575_detect);
132}
133
134/* This function is called by i2c_probe */
135static int pcf8575_detect(struct i2c_adapter *adapter, int address, int kind)
136{
137 struct i2c_client *client;
138 struct pcf8575_data *data;
139 int err = 0;
140
141 if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
142 goto exit;
143
144 /* OK. For now, we presume we have a valid client. We now create the
145 client structure, even though we cannot fill it completely yet. */
146 data = kzalloc(sizeof(struct pcf8575_data), GFP_KERNEL);
147 if (!data) {
148 err = -ENOMEM;
149 goto exit;
150 }
151
152 client = &data->client;
153 i2c_set_clientdata(client, data);
154 client->addr = address;
155 client->adapter = adapter;
156 client->driver = &pcf8575_driver;
157 strlcpy(client->name, "pcf8575", I2C_NAME_SIZE);
158 data->write = -EAGAIN;
159
160 /* This is the place to detect whether the chip at the specified
161 address really is a PCF8575 chip. However, there is no method known
162 to detect whether an I2C chip is a PCF8575 or any other I2C chip. */
163
164 /* Tell the I2C layer a new client has arrived */
165 err = i2c_attach_client(client);
166 if (err)
167 goto exit_free;
168
169 /* Register sysfs hooks */
170 err = sysfs_create_group(&client->dev.kobj, &pcf8575_attr_group);
171 if (err)
172 goto exit_detach;
173
174 return 0;
175
176exit_detach:
177 i2c_detach_client(client);
178exit_free:
179 kfree(data);
180exit:
181 return err;
182}
183
184static int pcf8575_detach_client(struct i2c_client *client)
185{
186 int err;
187
188 sysfs_remove_group(&client->dev.kobj, &pcf8575_attr_group);
189
190 err = i2c_detach_client(client);
191 if (err)
192 return err;
193
194 kfree(i2c_get_clientdata(client));
195 return 0;
196}
197
198static int __init pcf8575_init(void)
199{
200 return i2c_add_driver(&pcf8575_driver);
201}
202
203static void __exit pcf8575_exit(void)
204{
205 i2c_del_driver(&pcf8575_driver);
206}
207
208MODULE_AUTHOR("Michael Hennerich <hennerich@blackfin.uclinux.org>, "
209 "Bart Van Assche <bart.vanassche@gmail.com>");
210MODULE_DESCRIPTION("pcf8575 driver");
211MODULE_LICENSE("GPL");
212
213module_init(pcf8575_init);
214module_exit(pcf8575_exit);