diff options
author | Anton Vorontsov <cbouatmailru@gmail.com> | 2008-07-29 18:05:23 -0400 |
---|---|---|
committer | Anton Vorontsov <cbouatmailru@gmail.com> | 2008-07-29 18:05:23 -0400 |
commit | 9fec6060d9e48ed7db0dac0e16d0f0f0e615b7f6 (patch) | |
tree | 74b41f31a08f6500ff3dfcf64ba21e2d9a8e87e5 /drivers/i2c/chips/pcf8574.c | |
parent | fece418418f51e92dd7e67e17c5e3fe5a28d3279 (diff) | |
parent | 6e86841d05f371b5b9b86ce76c02aaee83352298 (diff) |
Merge branch 'master' of /home/cbou/linux-2.6
Conflicts:
drivers/power/Kconfig
drivers/power/Makefile
Diffstat (limited to 'drivers/i2c/chips/pcf8574.c')
-rw-r--r-- | drivers/i2c/chips/pcf8574.c | 115 |
1 files changed, 48 insertions, 67 deletions
diff --git a/drivers/i2c/chips/pcf8574.c b/drivers/i2c/chips/pcf8574.c index e5b31329b56e..6ec309894c88 100644 --- a/drivers/i2c/chips/pcf8574.c +++ b/drivers/i2c/chips/pcf8574.c | |||
@@ -1,6 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | pcf8574.c - Part of lm_sensors, Linux kernel modules for hardware | ||
3 | monitoring | ||
4 | Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>, | 2 | Copyright (c) 2000 Frodo Looijaard <frodol@dds.nl>, |
5 | Philip Edelbrock <phil@netroedge.com>, | 3 | Philip Edelbrock <phil@netroedge.com>, |
6 | Dan Eaton <dan.eaton@rocketlogix.com> | 4 | Dan Eaton <dan.eaton@rocketlogix.com> |
@@ -40,37 +38,19 @@ | |||
40 | #include <linux/slab.h> | 38 | #include <linux/slab.h> |
41 | #include <linux/i2c.h> | 39 | #include <linux/i2c.h> |
42 | 40 | ||
43 | /* Addresses to scan */ | 41 | /* Addresses to scan: none, device can't be detected */ |
44 | static const unsigned short normal_i2c[] = { | 42 | static const unsigned short normal_i2c[] = { I2C_CLIENT_END }; |
45 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, | ||
46 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, | ||
47 | I2C_CLIENT_END | ||
48 | }; | ||
49 | 43 | ||
50 | /* Insmod parameters */ | 44 | /* Insmod parameters */ |
51 | I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a); | 45 | I2C_CLIENT_INSMOD_2(pcf8574, pcf8574a); |
52 | 46 | ||
53 | /* Each client has this additional data */ | 47 | /* Each client has this additional data */ |
54 | struct pcf8574_data { | 48 | struct pcf8574_data { |
55 | struct i2c_client client; | ||
56 | |||
57 | int write; /* Remember last written value */ | 49 | int write; /* Remember last written value */ |
58 | }; | 50 | }; |
59 | 51 | ||
60 | static int pcf8574_attach_adapter(struct i2c_adapter *adapter); | ||
61 | static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind); | ||
62 | static int pcf8574_detach_client(struct i2c_client *client); | ||
63 | static void pcf8574_init_client(struct i2c_client *client); | 52 | static void pcf8574_init_client(struct i2c_client *client); |
64 | 53 | ||
65 | /* This is the driver that will be inserted */ | ||
66 | static struct i2c_driver pcf8574_driver = { | ||
67 | .driver = { | ||
68 | .name = "pcf8574", | ||
69 | }, | ||
70 | .attach_adapter = pcf8574_attach_adapter, | ||
71 | .detach_client = pcf8574_detach_client, | ||
72 | }; | ||
73 | |||
74 | /* following are the sysfs callback functions */ | 54 | /* following are the sysfs callback functions */ |
75 | 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) |
76 | { | 56 | { |
@@ -121,42 +101,22 @@ static const struct attribute_group pcf8574_attr_group = { | |||
121 | * Real code | 101 | * Real code |
122 | */ | 102 | */ |
123 | 103 | ||
124 | static int pcf8574_attach_adapter(struct i2c_adapter *adapter) | 104 | /* Return 0 if detection is successful, -ENODEV otherwise */ |
125 | { | 105 | static int pcf8574_detect(struct i2c_client *client, int kind, |
126 | return i2c_probe(adapter, &addr_data, pcf8574_detect); | 106 | struct i2c_board_info *info) |
127 | } | ||
128 | |||
129 | /* This function is called by i2c_probe */ | ||
130 | static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) | ||
131 | { | 107 | { |
132 | struct i2c_client *new_client; | 108 | struct i2c_adapter *adapter = client->adapter; |
133 | struct pcf8574_data *data; | 109 | const char *client_name; |
134 | int err = 0; | ||
135 | const char *client_name = ""; | ||
136 | 110 | ||
137 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) | 111 | if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) |
138 | goto exit; | 112 | return -ENODEV; |
139 | |||
140 | /* OK. For now, we presume we have a valid client. We now create the | ||
141 | client structure, even though we cannot fill it completely yet. */ | ||
142 | if (!(data = kzalloc(sizeof(struct pcf8574_data), GFP_KERNEL))) { | ||
143 | err = -ENOMEM; | ||
144 | goto exit; | ||
145 | } | ||
146 | |||
147 | new_client = &data->client; | ||
148 | i2c_set_clientdata(new_client, data); | ||
149 | new_client->addr = address; | ||
150 | new_client->adapter = adapter; | ||
151 | new_client->driver = &pcf8574_driver; | ||
152 | new_client->flags = 0; | ||
153 | 113 | ||
154 | /* 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 |
155 | impossible to detect! Stupid chip. */ | 115 | impossible to detect! Stupid chip. */ |
156 | 116 | ||
157 | /* Determine the chip type */ | 117 | /* Determine the chip type */ |
158 | if (kind <= 0) { | 118 | if (kind <= 0) { |
159 | if (address >= 0x38 && address <= 0x3f) | 119 | if (client->addr >= 0x38 && client->addr <= 0x3f) |
160 | kind = pcf8574a; | 120 | kind = pcf8574a; |
161 | else | 121 | else |
162 | kind = pcf8574; | 122 | kind = pcf8574; |
@@ -166,40 +126,43 @@ static int pcf8574_detect(struct i2c_adapter *adapter, int address, int kind) | |||
166 | client_name = "pcf8574a"; | 126 | client_name = "pcf8574a"; |
167 | else | 127 | else |
168 | client_name = "pcf8574"; | 128 | client_name = "pcf8574"; |
129 | strlcpy(info->type, client_name, I2C_NAME_SIZE); | ||
169 | 130 | ||
170 | /* Fill in the remaining client fields and put it into the global list */ | 131 | return 0; |
171 | strlcpy(new_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); | ||
172 | 147 | ||
173 | /* Tell the I2C layer a new client has arrived */ | ||
174 | if ((err = i2c_attach_client(new_client))) | ||
175 | goto exit_free; | ||
176 | |||
177 | /* Initialize the PCF8574 chip */ | 148 | /* Initialize the PCF8574 chip */ |
178 | pcf8574_init_client(new_client); | 149 | pcf8574_init_client(client); |
179 | 150 | ||
180 | /* Register sysfs hooks */ | 151 | /* Register sysfs hooks */ |
181 | err = sysfs_create_group(&new_client->dev.kobj, &pcf8574_attr_group); | 152 | err = sysfs_create_group(&client->dev.kobj, &pcf8574_attr_group); |
182 | if (err) | 153 | if (err) |
183 | goto exit_detach; | 154 | goto exit_free; |
184 | return 0; | 155 | return 0; |
185 | 156 | ||
186 | exit_detach: | ||
187 | i2c_detach_client(new_client); | ||
188 | exit_free: | 157 | exit_free: |
189 | kfree(data); | 158 | kfree(data); |
190 | exit: | 159 | exit: |
191 | return err; | 160 | return err; |
192 | } | 161 | } |
193 | 162 | ||
194 | static int pcf8574_detach_client(struct i2c_client *client) | 163 | static int pcf8574_remove(struct i2c_client *client) |
195 | { | 164 | { |
196 | int err; | ||
197 | |||
198 | sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group); | 165 | sysfs_remove_group(&client->dev.kobj, &pcf8574_attr_group); |
199 | |||
200 | if ((err = i2c_detach_client(client))) | ||
201 | return err; | ||
202 | |||
203 | kfree(i2c_get_clientdata(client)); | 166 | kfree(i2c_get_clientdata(client)); |
204 | return 0; | 167 | return 0; |
205 | } | 168 | } |
@@ -211,6 +174,24 @@ static void pcf8574_init_client(struct i2c_client *client) | |||
211 | data->write = -EAGAIN; | 174 | data->write = -EAGAIN; |
212 | } | 175 | } |
213 | 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 | |||
214 | static int __init pcf8574_init(void) | 195 | static int __init pcf8574_init(void) |
215 | { | 196 | { |
216 | return i2c_add_driver(&pcf8574_driver); | 197 | return i2c_add_driver(&pcf8574_driver); |