diff options
Diffstat (limited to 'drivers/i2c')
-rw-r--r-- | drivers/i2c/i2c-core.c | 67 |
1 files changed, 47 insertions, 20 deletions
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c index 0e45c296d3d2..f236b34296ee 100644 --- a/drivers/i2c/i2c-core.c +++ b/drivers/i2c/i2c-core.c | |||
@@ -64,9 +64,13 @@ static const struct i2c_device_id *i2c_match_id(const struct i2c_device_id *id, | |||
64 | 64 | ||
65 | static int i2c_device_match(struct device *dev, struct device_driver *drv) | 65 | static int i2c_device_match(struct device *dev, struct device_driver *drv) |
66 | { | 66 | { |
67 | struct i2c_client *client = to_i2c_client(dev); | 67 | struct i2c_client *client = i2c_verify_client(dev); |
68 | struct i2c_driver *driver = to_i2c_driver(drv); | 68 | struct i2c_driver *driver; |
69 | 69 | ||
70 | if (!client) | ||
71 | return 0; | ||
72 | |||
73 | driver = to_i2c_driver(drv); | ||
70 | /* match on an id table if there is one */ | 74 | /* match on an id table if there is one */ |
71 | if (driver->id_table) | 75 | if (driver->id_table) |
72 | return i2c_match_id(driver->id_table, client) != NULL; | 76 | return i2c_match_id(driver->id_table, client) != NULL; |
@@ -94,10 +98,14 @@ static int i2c_device_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
94 | 98 | ||
95 | static int i2c_device_probe(struct device *dev) | 99 | static int i2c_device_probe(struct device *dev) |
96 | { | 100 | { |
97 | struct i2c_client *client = to_i2c_client(dev); | 101 | struct i2c_client *client = i2c_verify_client(dev); |
98 | struct i2c_driver *driver = to_i2c_driver(dev->driver); | 102 | struct i2c_driver *driver; |
99 | int status; | 103 | int status; |
100 | 104 | ||
105 | if (!client) | ||
106 | return 0; | ||
107 | |||
108 | driver = to_i2c_driver(dev->driver); | ||
101 | if (!driver->probe || !driver->id_table) | 109 | if (!driver->probe || !driver->id_table) |
102 | return -ENODEV; | 110 | return -ENODEV; |
103 | client->driver = driver; | 111 | client->driver = driver; |
@@ -114,11 +122,11 @@ static int i2c_device_probe(struct device *dev) | |||
114 | 122 | ||
115 | static int i2c_device_remove(struct device *dev) | 123 | static int i2c_device_remove(struct device *dev) |
116 | { | 124 | { |
117 | struct i2c_client *client = to_i2c_client(dev); | 125 | struct i2c_client *client = i2c_verify_client(dev); |
118 | struct i2c_driver *driver; | 126 | struct i2c_driver *driver; |
119 | int status; | 127 | int status; |
120 | 128 | ||
121 | if (!dev->driver) | 129 | if (!client || !dev->driver) |
122 | return 0; | 130 | return 0; |
123 | 131 | ||
124 | driver = to_i2c_driver(dev->driver); | 132 | driver = to_i2c_driver(dev->driver); |
@@ -136,37 +144,40 @@ static int i2c_device_remove(struct device *dev) | |||
136 | 144 | ||
137 | static void i2c_device_shutdown(struct device *dev) | 145 | static void i2c_device_shutdown(struct device *dev) |
138 | { | 146 | { |
147 | struct i2c_client *client = i2c_verify_client(dev); | ||
139 | struct i2c_driver *driver; | 148 | struct i2c_driver *driver; |
140 | 149 | ||
141 | if (!dev->driver) | 150 | if (!client || !dev->driver) |
142 | return; | 151 | return; |
143 | driver = to_i2c_driver(dev->driver); | 152 | driver = to_i2c_driver(dev->driver); |
144 | if (driver->shutdown) | 153 | if (driver->shutdown) |
145 | driver->shutdown(to_i2c_client(dev)); | 154 | driver->shutdown(client); |
146 | } | 155 | } |
147 | 156 | ||
148 | static int i2c_device_suspend(struct device *dev, pm_message_t mesg) | 157 | static int i2c_device_suspend(struct device *dev, pm_message_t mesg) |
149 | { | 158 | { |
159 | struct i2c_client *client = i2c_verify_client(dev); | ||
150 | struct i2c_driver *driver; | 160 | struct i2c_driver *driver; |
151 | 161 | ||
152 | if (!dev->driver) | 162 | if (!client || !dev->driver) |
153 | return 0; | 163 | return 0; |
154 | driver = to_i2c_driver(dev->driver); | 164 | driver = to_i2c_driver(dev->driver); |
155 | if (!driver->suspend) | 165 | if (!driver->suspend) |
156 | return 0; | 166 | return 0; |
157 | return driver->suspend(to_i2c_client(dev), mesg); | 167 | return driver->suspend(client, mesg); |
158 | } | 168 | } |
159 | 169 | ||
160 | static int i2c_device_resume(struct device *dev) | 170 | static int i2c_device_resume(struct device *dev) |
161 | { | 171 | { |
172 | struct i2c_client *client = i2c_verify_client(dev); | ||
162 | struct i2c_driver *driver; | 173 | struct i2c_driver *driver; |
163 | 174 | ||
164 | if (!dev->driver) | 175 | if (!client || !dev->driver) |
165 | return 0; | 176 | return 0; |
166 | driver = to_i2c_driver(dev->driver); | 177 | driver = to_i2c_driver(dev->driver); |
167 | if (!driver->resume) | 178 | if (!driver->resume) |
168 | return 0; | 179 | return 0; |
169 | return driver->resume(to_i2c_client(dev)); | 180 | return driver->resume(client); |
170 | } | 181 | } |
171 | 182 | ||
172 | static void i2c_client_dev_release(struct device *dev) | 183 | static void i2c_client_dev_release(struct device *dev) |
@@ -188,18 +199,28 @@ show_modalias(struct device *dev, struct device_attribute *attr, char *buf) | |||
188 | return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); | 199 | return sprintf(buf, "%s%s\n", I2C_MODULE_PREFIX, client->name); |
189 | } | 200 | } |
190 | 201 | ||
191 | static struct device_attribute i2c_dev_attrs[] = { | 202 | static DEVICE_ATTR(name, S_IRUGO, show_client_name, NULL); |
192 | __ATTR(name, S_IRUGO, show_client_name, NULL), | 203 | static DEVICE_ATTR(modalias, S_IRUGO, show_modalias, NULL); |
204 | |||
205 | static struct attribute *i2c_dev_attrs[] = { | ||
206 | &dev_attr_name.attr, | ||
193 | /* modalias helps coldplug: modprobe $(cat .../modalias) */ | 207 | /* modalias helps coldplug: modprobe $(cat .../modalias) */ |
194 | __ATTR(modalias, S_IRUGO, show_modalias, NULL), | 208 | &dev_attr_modalias.attr, |
195 | { }, | 209 | NULL |
210 | }; | ||
211 | |||
212 | static struct attribute_group i2c_dev_attr_group = { | ||
213 | .attrs = i2c_dev_attrs, | ||
214 | }; | ||
215 | |||
216 | static const struct attribute_group *i2c_dev_attr_groups[] = { | ||
217 | &i2c_dev_attr_group, | ||
218 | NULL | ||
196 | }; | 219 | }; |
197 | 220 | ||
198 | struct bus_type i2c_bus_type = { | 221 | struct bus_type i2c_bus_type = { |
199 | .name = "i2c", | 222 | .name = "i2c", |
200 | .dev_attrs = i2c_dev_attrs, | ||
201 | .match = i2c_device_match, | 223 | .match = i2c_device_match, |
202 | .uevent = i2c_device_uevent, | ||
203 | .probe = i2c_device_probe, | 224 | .probe = i2c_device_probe, |
204 | .remove = i2c_device_remove, | 225 | .remove = i2c_device_remove, |
205 | .shutdown = i2c_device_shutdown, | 226 | .shutdown = i2c_device_shutdown, |
@@ -208,6 +229,12 @@ struct bus_type i2c_bus_type = { | |||
208 | }; | 229 | }; |
209 | EXPORT_SYMBOL_GPL(i2c_bus_type); | 230 | EXPORT_SYMBOL_GPL(i2c_bus_type); |
210 | 231 | ||
232 | static struct device_type i2c_client_type = { | ||
233 | .groups = i2c_dev_attr_groups, | ||
234 | .uevent = i2c_device_uevent, | ||
235 | .release = i2c_client_dev_release, | ||
236 | }; | ||
237 | |||
211 | 238 | ||
212 | /** | 239 | /** |
213 | * i2c_verify_client - return parameter as i2c_client, or NULL | 240 | * i2c_verify_client - return parameter as i2c_client, or NULL |
@@ -220,7 +247,7 @@ EXPORT_SYMBOL_GPL(i2c_bus_type); | |||
220 | */ | 247 | */ |
221 | struct i2c_client *i2c_verify_client(struct device *dev) | 248 | struct i2c_client *i2c_verify_client(struct device *dev) |
222 | { | 249 | { |
223 | return (dev->bus == &i2c_bus_type) | 250 | return (dev->type == &i2c_client_type) |
224 | ? to_i2c_client(dev) | 251 | ? to_i2c_client(dev) |
225 | : NULL; | 252 | : NULL; |
226 | } | 253 | } |
@@ -273,7 +300,7 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) | |||
273 | 300 | ||
274 | client->dev.parent = &client->adapter->dev; | 301 | client->dev.parent = &client->adapter->dev; |
275 | client->dev.bus = &i2c_bus_type; | 302 | client->dev.bus = &i2c_bus_type; |
276 | client->dev.release = i2c_client_dev_release; | 303 | client->dev.type = &i2c_client_type; |
277 | 304 | ||
278 | dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), | 305 | dev_set_name(&client->dev, "%d-%04x", i2c_adapter_id(adap), |
279 | client->addr); | 306 | client->addr); |