diff options
-rw-r--r-- | Documentation/i2c/chips/pcf8574 | 12 | ||||
-rw-r--r-- | drivers/i2c/chips/pcf8574.c | 108 |
2 files changed, 51 insertions, 69 deletions
diff --git a/Documentation/i2c/chips/pcf8574 b/Documentation/i2c/chips/pcf8574 index 5c1ad1376b62..235815c075ff 100644 --- a/Documentation/i2c/chips/pcf8574 +++ b/Documentation/i2c/chips/pcf8574 | |||
@@ -4,13 +4,13 @@ Kernel driver pcf8574 | |||
4 | Supported chips: | 4 | Supported chips: |
5 | * Philips PCF8574 | 5 | * Philips PCF8574 |
6 | Prefix: 'pcf8574' | 6 | Prefix: 'pcf8574' |
7 | Addresses scanned: I2C 0x20 - 0x27 | 7 | Addresses scanned: none |
8 | Datasheet: Publicly available at the Philips Semiconductors website | 8 | Datasheet: Publicly available at the Philips Semiconductors website |
9 | http://www.semiconductors.philips.com/pip/PCF8574P.html | 9 | http://www.semiconductors.philips.com/pip/PCF8574P.html |
10 | 10 | ||
11 | * Philips PCF8574A | 11 | * Philips PCF8574A |
12 | Prefix: 'pcf8574a' | 12 | Prefix: 'pcf8574a' |
13 | Addresses scanned: I2C 0x38 - 0x3f | 13 | Addresses scanned: none |
14 | Datasheet: Publicly available at the Philips Semiconductors website | 14 | Datasheet: Publicly available at the Philips Semiconductors website |
15 | http://www.semiconductors.philips.com/pip/PCF8574P.html | 15 | http://www.semiconductors.philips.com/pip/PCF8574P.html |
16 | 16 | ||
@@ -38,12 +38,10 @@ For more informations see the datasheet. | |||
38 | Accessing PCF8574(A) via /sys interface | 38 | Accessing PCF8574(A) via /sys interface |
39 | ------------------------------------- | 39 | ------------------------------------- |
40 | 40 | ||
41 | ! Be careful ! | ||
42 | The PCF8574(A) is plainly impossible to detect ! Stupid chip. | 41 | The PCF8574(A) is plainly impossible to detect ! Stupid chip. |
43 | So every chip with address in the interval [20..27] and [38..3f] are | 42 | So, you have to pass the I2C bus and address of the installed PCF857A |
44 | detected as PCF8574(A). If you have other chips in this address | 43 | and PCF8574A devices explicitly to the driver at load time via the |
45 | range, the workaround is to load this module after the one | 44 | force=... parameter. |
46 | for your others chips. | ||
47 | 45 | ||
48 | On detection (i.e. insmod, modprobe et al.), directories are being | 46 | On detection (i.e. insmod, modprobe et al.), directories are being |
49 | created for each detected PCF8574(A): | 47 | created for each detected PCF8574(A): |
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index 1b3db2b3ada9..6ec309894c88 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c | |||
@@ -38,37 +38,19 @@ | |||
38 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
39 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
40 | 40 | ||
41 | /* Addresses to scan */ | 41 | /* Addresses to scan: none, device can't be detected */ |
42 | static const unsigned short normal_i2c[] = { | 42 | static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; |
43 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
44 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, | ||
45 | I2C_CLIENT_END | ||
46 | }; | ||
47 | 43 | ||
48 | /* Insmod parameters */ | 44 | /* Insmod parameters */ |
49 | I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a); | 45 | I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a); |
50 | 46 | ||
51 | /* Each client has this additional data */ | 47 | /* Each client has this additional data */ |
52 | struct pcf8574_data { | 48 | struct pcf8574_data { |
53 | struct i2c_client client; | ||
54 | |||
55 | int write; /* Remember last written value */ | 49 | int write; /* Remember last written value */ |
56 | }; | 50 | }; |
57 | 51 | ||
58 | static int pcf8574_attach_adapter(struct i2c_adapter *adapter); | ||
59 | static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind); | ||
60 | static int pcf8574_detach_client(struct i2c_client *client); | ||
61 | static void pcf8574_init_client(struct i2c_client *client); | 52 | static void pcf8574_init_client(struct i2c_client *client); |
62 | 53 | ||
63 | /* This is the driver that will be inserted */ | ||
64 | static struct i2c_driver pcf8574_driver = { | ||
65 | .driver = { | ||
66 | .name = "pcf8574", | ||
67 | }, | ||
68 | .attach_adapter = pcf8574_attach_adapter, | ||
69 | .detach_client = pcf8574_detach_client, | ||
70 | }; | ||
71 | |||
72 | /* following are the sysfs callback functions */ | 54 | /* following are the sysfs callback functions */ |
73 | static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf) | 55 | static ssize_t show_read(struct device *dev, struct device_attribute *attr, char *buf) |
74 | { | 56 | { |
@@ -119,41 +101,22 @@ static const struct attribute_group pcf8574_attr_group = { | |||
119 | * Real code | 101 | * Real code |
120 | */ | 102 | */ |
121 | 103 | ||
122 | static int pcf8574_attach_adapter(struct i2c_adapter *adapter) | 104 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
123 | { | 105 | static int pcf8574_detect(struct i2c_client *client, int kind, |
124 | return i2c_probe(adapter, &addr_data, pcf8574_detect); | 106 | struct i2c_board_info *info) |
125 | } | ||
126 | |||
127 | /* This function is called by i2c_probe */ | ||
128 | static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) | ||
129 | { | 107 | { |
130 | struct i2c_client *client; | 108 | struct i2c_adapter *adapter = client->adapter; |
131 | struct pcf8574_data *data; | 109 | const char *client_name; |
132 | int err = 0; | ||
133 | const char *client_name = ""; | ||
134 | 110 | ||
135 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) | 111 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) |
136 | goto exit; | 112 | return -ENODEV; |
137 | |||
138 | /* OK. For now, we presume we have a valid client. We now create the | ||
139 | client structure, even though we cannot fill it completely yet. */ | ||
140 | if (!(data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { | ||
141 | err = -ENOMEM; | ||
142 | goto exit; | ||
143 | } | ||
144 | |||
145 | client = &data->client; | ||
146 | i2c_set_clientdata(client, data); | ||
147 | client->addr = address; | ||
148 | client->adapter = adapter; | ||
149 | client->driver = &pcf8574_driver; | ||
150 | 113 | ||
151 | /* Now, we would do the remaining detection. But the PCF8574 is plainly | 114 | /* Now, we would do the remaining detection. But the PCF8574 is plainly |
152 | impossible to detect! Stupid chip. */ | 115 | impossible to detect! Stupid chip. */ |
153 | 116 | ||
154 | /* Determine the chip type */ | 117 | /* Determine the chip type */ |
155 | if (kind <= 0) { | 118 | if (kind <= 0) { |
156 | if (address >= 0x38 && address <= 0x3f) | 119 | if (client->addr >= 0x38 && client->addr <= 0x3f) |
157 | kind = pcf8574a; | 120 | kind = pcf8574a; |
158 | else | 121 | else |
159 | kind = pcf8574; | 122 | kind = pcf8574; |
@@ -163,40 +126,43 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) | |||
163 | client_name = "pcf8574a"; | 126 | client_name = "pcf8574a"; |
164 | else | 127 | else |
165 | client_name = "pcf8574"; | 128 | client_name = "pcf8574"; |
129 | strlcpy(info->type, client_name, I2C_NAME_SIZE); | ||
166 | 130 | ||
167 | /* Fill in the remaining client fields and put it into the global list */ | 131 | return 0; |
168 | strlcpy(client->name, client_name, I2C_NAME_SIZE); | 132 | } |
133 | |||
134 | static int pcf8574_probe(struct i2c_client *client, | ||
135 | const struct i2c_device_id *id) | ||
136 | { | ||
137 | struct pcf8574_data *data; | ||
138 | int err; | ||
139 | |||
140 | data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL); | ||
141 | if (!data) { | ||
142 | err = -ENOMEM; | ||
143 | goto exit; | ||
144 | } | ||
145 | |||
146 | i2c_set_clientdata(client, data); | ||
169 | 147 | ||
170 | /* Tell the I2C layer a new client has arrived */ | ||
171 | if ((err = i2c_attach_client(client))) | ||
172 | goto exit_free; | ||
173 | |||
174 | /* Initialize the PCF8574 chip */ | 148 | /* Initialize the PCF8574 chip */ |
175 | pcf8574_init_client(client); | 149 | pcf8574_init_client(client); |
176 | 150 | ||
177 | /* Register sysfs hooks */ | 151 | /* Register sysfs hooks */ |
178 | err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group); | 152 | err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group); |
179 | if (err) | 153 | if (err) |
180 | goto exit_detach; | 154 | goto exit_free; |
181 | return 0; | 155 | return 0; |
182 | 156 | ||
183 | exit_detach: | ||
184 | i2c_detach_client(client); | ||
185 | exit_free: | 157 | exit_free: |
186 | kfree(data); | 158 | kfree(data); |
187 | exit: | 159 | exit: |
188 | return err; | 160 | return err; |
189 | } | 161 | } |
190 | 162 | ||
191 | static int pcf8574_detach_client(struct i2c_client *client) | 163 | static int pcf8574_remove(struct i2c_client *client) |
192 | { | 164 | { |
193 | int err; | ||
194 | |||
195 | sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group); | 165 | sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group); |
196 | |||
197 | if ((err = i2c_detach_client(client))) | ||
198 | return err; | ||
199 | |||
200 | kfree(i2c_get_clientdata(client)); | 166 | kfree(i2c_get_clientdata(client)); |
201 | return 0; | 167 | return 0; |
202 | } | 168 | } |
@@ -208,6 +174,24 @@ static void pcf8574_init_client(struct i2c_client *client) | |||
208 | data->write = -EAGAIN; | 174 | data->write = -EAGAIN; |
209 | } | 175 | } |
210 | 176 | ||
177 | static const struct i2c_device_id pcf8574_id[] = { | ||
178 | { "pcf8574", 0 }, | ||
179 | { "pcf8574a", 0 }, | ||
180 | { } | ||
181 | }; | ||
182 | |||
183 | static struct i2c_driver pcf8574_driver = { | ||
184 | .driver = { | ||
185 | .name = "pcf8574", | ||
186 | }, | ||
187 | .probe = pcf8574_probe, | ||
188 | .remove = pcf8574_remove, | ||
189 | .id_table = pcf8574_id, | ||
190 | |||
191 | .detect = pcf8574_detect, | ||
192 | .address_data = &addr_data, | ||
193 | }; | ||
194 | |||
211 | static int __init pcf8574_init(void) | 195 | static int __init pcf8574_init(void) |
212 | { | 196 | { |
213 | return i2c_add_driver(&pcf8574_driver); | 197 | return i2c_add_driver(&pcf8574_driver); |