diff options
author | Benson Leung <bleung@chromium.org> | 2013-10-20 23:58:25 -0400 |
---|---|---|
committer | Olof Johansson <olof@lixom.net> | 2013-11-25 15:51:09 -0500 |
commit | 9ad3692458c387eb9537da73b2b75841ed7acdaf (patch) | |
tree | f9504a0bfb1938ab6d38be5d914e8cbbcfe8a5b6 /drivers/platform | |
parent | ec199dd57ef71858b53828283ac495ed82164933 (diff) |
platform/chrome: chromeos_laptop - Use deferred probing
Further refactor chromeos_laptop, adding a probe function.
Init will call dmi_check_system, but will only use the match to select
a chromeos_laptop structure of the current board.
Probe will add the devices, and on errors return -EPROBE_DEFER.
If i2c adapters are loaded after chromeos_laptop inits, the deferred
probe will instantiate the peripherals when the bus appears.
Signed-off-by: Benson Leung <bleung@chromium.org>
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
Signed-off-by: Olof Johansson <olof@lixom.net>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/chrome/chromeos_laptop.c | 144 |
1 files changed, 101 insertions, 43 deletions
diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index 5c69cfd97ff0..e542330f8048 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c | |||
@@ -27,6 +27,7 @@ | |||
27 | #include <linux/input.h> | 27 | #include <linux/input.h> |
28 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/platform_device.h> | ||
30 | 31 | ||
31 | #define ATMEL_TP_I2C_ADDR 0x4b | 32 | #define ATMEL_TP_I2C_ADDR 0x4b |
32 | #define ATMEL_TP_I2C_BL_ADDR 0x25 | 33 | #define ATMEL_TP_I2C_BL_ADDR 0x25 |
@@ -54,7 +55,7 @@ enum i2c_adapter_type { | |||
54 | }; | 55 | }; |
55 | 56 | ||
56 | struct i2c_peripheral { | 57 | struct i2c_peripheral { |
57 | void (*add)(enum i2c_adapter_type type); | 58 | int (*add)(enum i2c_adapter_type type); |
58 | enum i2c_adapter_type type; | 59 | enum i2c_adapter_type type; |
59 | }; | 60 | }; |
60 | 61 | ||
@@ -64,20 +65,22 @@ struct chromeos_laptop { | |||
64 | struct i2c_peripheral i2c_peripherals[MAX_I2C_PERIPHERALS]; | 65 | struct i2c_peripheral i2c_peripherals[MAX_I2C_PERIPHERALS]; |
65 | }; | 66 | }; |
66 | 67 | ||
67 | static struct i2c_board_info __initdata cyapa_device = { | 68 | static struct chromeos_laptop *cros_laptop; |
69 | |||
70 | static struct i2c_board_info cyapa_device = { | ||
68 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), | 71 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), |
69 | .flags = I2C_CLIENT_WAKE, | 72 | .flags = I2C_CLIENT_WAKE, |
70 | }; | 73 | }; |
71 | 74 | ||
72 | static struct i2c_board_info __initdata isl_als_device = { | 75 | static struct i2c_board_info isl_als_device = { |
73 | I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), | 76 | I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), |
74 | }; | 77 | }; |
75 | 78 | ||
76 | static struct i2c_board_info __initdata tsl2583_als_device = { | 79 | static struct i2c_board_info tsl2583_als_device = { |
77 | I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR), | 80 | I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR), |
78 | }; | 81 | }; |
79 | 82 | ||
80 | static struct i2c_board_info __initdata tsl2563_als_device = { | 83 | static struct i2c_board_info tsl2563_als_device = { |
81 | I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR), | 84 | I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR), |
82 | }; | 85 | }; |
83 | 86 | ||
@@ -100,7 +103,7 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = { | |||
100 | .config_length = 0, | 103 | .config_length = 0, |
101 | }; | 104 | }; |
102 | 105 | ||
103 | static struct i2c_board_info __initdata atmel_224s_tp_device = { | 106 | static struct i2c_board_info atmel_224s_tp_device = { |
104 | I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR), | 107 | I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR), |
105 | .platform_data = &atmel_224s_tp_platform_data, | 108 | .platform_data = &atmel_224s_tp_platform_data, |
106 | .flags = I2C_CLIENT_WAKE, | 109 | .flags = I2C_CLIENT_WAKE, |
@@ -121,13 +124,13 @@ static struct mxt_platform_data atmel_1664s_platform_data = { | |||
121 | .config_length = 0, | 124 | .config_length = 0, |
122 | }; | 125 | }; |
123 | 126 | ||
124 | static struct i2c_board_info __initdata atmel_1664s_device = { | 127 | static struct i2c_board_info atmel_1664s_device = { |
125 | I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR), | 128 | I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR), |
126 | .platform_data = &atmel_1664s_platform_data, | 129 | .platform_data = &atmel_1664s_platform_data, |
127 | .flags = I2C_CLIENT_WAKE, | 130 | .flags = I2C_CLIENT_WAKE, |
128 | }; | 131 | }; |
129 | 132 | ||
130 | static struct i2c_client __init *__add_probed_i2c_device( | 133 | static struct i2c_client *__add_probed_i2c_device( |
131 | const char *name, | 134 | const char *name, |
132 | int bus, | 135 | int bus, |
133 | struct i2c_board_info *info, | 136 | struct i2c_board_info *info, |
@@ -180,7 +183,7 @@ static struct i2c_client __init *__add_probed_i2c_device( | |||
180 | return client; | 183 | return client; |
181 | } | 184 | } |
182 | 185 | ||
183 | static int __init __find_i2c_adap(struct device *dev, void *data) | 186 | static int __find_i2c_adap(struct device *dev, void *data) |
184 | { | 187 | { |
185 | const char *name = data; | 188 | const char *name = data; |
186 | static const char *prefix = "i2c-"; | 189 | static const char *prefix = "i2c-"; |
@@ -191,7 +194,7 @@ static int __init __find_i2c_adap(struct device *dev, void *data) | |||
191 | return (strncmp(adapter->name, name, strlen(name)) == 0); | 194 | return (strncmp(adapter->name, name, strlen(name)) == 0); |
192 | } | 195 | } |
193 | 196 | ||
194 | static int __init find_i2c_adapter_num(enum i2c_adapter_type type) | 197 | static int find_i2c_adapter_num(enum i2c_adapter_type type) |
195 | { | 198 | { |
196 | struct device *dev = NULL; | 199 | struct device *dev = NULL; |
197 | struct i2c_adapter *adapter; | 200 | struct i2c_adapter *adapter; |
@@ -200,8 +203,9 @@ static int __init find_i2c_adapter_num(enum i2c_adapter_type type) | |||
200 | dev = bus_find_device(&i2c_bus_type, NULL, (void *)name, | 203 | dev = bus_find_device(&i2c_bus_type, NULL, (void *)name, |
201 | __find_i2c_adap); | 204 | __find_i2c_adap); |
202 | if (!dev) { | 205 | if (!dev) { |
203 | pr_err("%s: i2c adapter %s not found on system.\n", __func__, | 206 | /* Adapters may appear later. Deferred probing will retry */ |
204 | name); | 207 | pr_notice("%s: i2c adapter %s not found on system.\n", __func__, |
208 | name); | ||
205 | return -ENODEV; | 209 | return -ENODEV; |
206 | } | 210 | } |
207 | adapter = to_i2c_adapter(dev); | 211 | adapter = to_i2c_adapter(dev); |
@@ -216,7 +220,7 @@ static int __init find_i2c_adapter_num(enum i2c_adapter_type type) | |||
216 | * Returns NULL if no devices found. | 220 | * Returns NULL if no devices found. |
217 | * See Documentation/i2c/instantiating-devices for more information. | 221 | * See Documentation/i2c/instantiating-devices for more information. |
218 | */ | 222 | */ |
219 | static __init struct i2c_client *add_probed_i2c_device( | 223 | static struct i2c_client *add_probed_i2c_device( |
220 | const char *name, | 224 | const char *name, |
221 | enum i2c_adapter_type type, | 225 | enum i2c_adapter_type type, |
222 | struct i2c_board_info *info, | 226 | struct i2c_board_info *info, |
@@ -233,7 +237,7 @@ static __init struct i2c_client *add_probed_i2c_device( | |||
233 | * info->addr. | 237 | * info->addr. |
234 | * Returns NULL if no device found. | 238 | * Returns NULL if no device found. |
235 | */ | 239 | */ |
236 | static __init struct i2c_client *add_i2c_device(const char *name, | 240 | static struct i2c_client *add_i2c_device(const char *name, |
237 | enum i2c_adapter_type type, | 241 | enum i2c_adapter_type type, |
238 | struct i2c_board_info *info) | 242 | struct i2c_board_info *info) |
239 | { | 243 | { |
@@ -244,65 +248,87 @@ static __init struct i2c_client *add_i2c_device(const char *name, | |||
244 | addr_list); | 248 | addr_list); |
245 | } | 249 | } |
246 | 250 | ||
247 | static int __init setup_cyapa_tp(enum i2c_adapter_type type) | 251 | static int setup_cyapa_tp(enum i2c_adapter_type type) |
248 | { | 252 | { |
253 | if (tp) | ||
254 | return 0; | ||
255 | |||
249 | /* add cyapa touchpad */ | 256 | /* add cyapa touchpad */ |
250 | tp = add_i2c_device("trackpad", type, &cyapa_device); | 257 | tp = add_i2c_device("trackpad", type, &cyapa_device); |
251 | return 0; | 258 | return (!tp) ? -EAGAIN : 0; |
252 | } | 259 | } |
253 | 260 | ||
254 | static int __init setup_atmel_224s_tp(enum i2c_adapter_type type) | 261 | static int setup_atmel_224s_tp(enum i2c_adapter_type type) |
255 | { | 262 | { |
256 | const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR, | 263 | const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR, |
257 | ATMEL_TP_I2C_ADDR, | 264 | ATMEL_TP_I2C_ADDR, |
258 | I2C_CLIENT_END }; | 265 | I2C_CLIENT_END }; |
266 | if (tp) | ||
267 | return 0; | ||
259 | 268 | ||
260 | /* add atmel mxt touchpad */ | 269 | /* add atmel mxt touchpad */ |
261 | tp = add_probed_i2c_device("trackpad", type, | 270 | tp = add_probed_i2c_device("trackpad", type, |
262 | &atmel_224s_tp_device, addr_list); | 271 | &atmel_224s_tp_device, addr_list); |
263 | return 0; | 272 | return (!tp) ? -EAGAIN : 0; |
264 | } | 273 | } |
265 | 274 | ||
266 | static int __init setup_atmel_1664s_ts(enum i2c_adapter_type type) | 275 | static int setup_atmel_1664s_ts(enum i2c_adapter_type type) |
267 | { | 276 | { |
268 | const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR, | 277 | const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR, |
269 | ATMEL_TS_I2C_ADDR, | 278 | ATMEL_TS_I2C_ADDR, |
270 | I2C_CLIENT_END }; | 279 | I2C_CLIENT_END }; |
280 | if (ts) | ||
281 | return 0; | ||
271 | 282 | ||
272 | /* add atmel mxt touch device */ | 283 | /* add atmel mxt touch device */ |
273 | ts = add_probed_i2c_device("touchscreen", type, | 284 | ts = add_probed_i2c_device("touchscreen", type, |
274 | &atmel_1664s_device, addr_list); | 285 | &atmel_1664s_device, addr_list); |
275 | return 0; | 286 | return (!ts) ? -EAGAIN : 0; |
276 | } | 287 | } |
277 | 288 | ||
278 | static int __init setup_isl29018_als(enum i2c_adapter_type type) | 289 | static int setup_isl29018_als(enum i2c_adapter_type type) |
279 | { | 290 | { |
291 | if (als) | ||
292 | return 0; | ||
293 | |||
280 | /* add isl29018 light sensor */ | 294 | /* add isl29018 light sensor */ |
281 | als = add_i2c_device("lightsensor", type, &isl_als_device); | 295 | als = add_i2c_device("lightsensor", type, &isl_als_device); |
282 | return 0; | 296 | return (!als) ? -EAGAIN : 0; |
283 | } | 297 | } |
284 | 298 | ||
285 | static int __init setup_tsl2583_als(enum i2c_adapter_type type) | 299 | static int setup_tsl2583_als(enum i2c_adapter_type type) |
286 | { | 300 | { |
301 | if (als) | ||
302 | return 0; | ||
303 | |||
287 | /* add tsl2583 light sensor */ | 304 | /* add tsl2583 light sensor */ |
288 | als = add_i2c_device(NULL, type, &tsl2583_als_device); | 305 | als = add_i2c_device(NULL, type, &tsl2583_als_device); |
289 | return 0; | 306 | return (!als) ? -EAGAIN : 0; |
290 | } | 307 | } |
291 | 308 | ||
292 | static int __init setup_tsl2563_als(enum i2c_adapter_type type) | 309 | static int setup_tsl2563_als(enum i2c_adapter_type type) |
293 | { | 310 | { |
311 | if (als) | ||
312 | return 0; | ||
313 | |||
294 | /* add tsl2563 light sensor */ | 314 | /* add tsl2563 light sensor */ |
295 | als = add_i2c_device(NULL, type, &tsl2563_als_device); | 315 | als = add_i2c_device(NULL, type, &tsl2563_als_device); |
296 | return 0; | 316 | return (!als) ? -EAGAIN : 0; |
297 | } | 317 | } |
298 | 318 | ||
299 | static int __init | 319 | static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id) |
300 | chromeos_laptop_add_peripherals(const struct dmi_system_id *id) | ||
301 | { | 320 | { |
302 | int i; | 321 | cros_laptop = (void *)id->driver_data; |
303 | struct chromeos_laptop *cros_laptop = (void *)id->driver_data; | 322 | pr_debug("DMI Matched %s.\n", id->ident); |
304 | 323 | ||
305 | pr_debug("Adding peripherals for %s.\n", id->ident); | 324 | /* Indicate to dmi_scan that processing is done. */ |
325 | return 1; | ||
326 | } | ||
327 | |||
328 | static int chromeos_laptop_probe(struct platform_device *pdev) | ||
329 | { | ||
330 | int i; | ||
331 | int ret = 0; | ||
306 | 332 | ||
307 | for (i = 0; i < MAX_I2C_PERIPHERALS; i++) { | 333 | for (i = 0; i < MAX_I2C_PERIPHERALS; i++) { |
308 | struct i2c_peripheral *i2c_dev; | 334 | struct i2c_peripheral *i2c_dev; |
@@ -313,15 +339,15 @@ chromeos_laptop_add_peripherals(const struct dmi_system_id *id) | |||
313 | if (i2c_dev->add == NULL) | 339 | if (i2c_dev->add == NULL) |
314 | break; | 340 | break; |
315 | 341 | ||
316 | /* Add the device. */ | 342 | /* Add the device. Set -EPROBE_DEFER on any failure */ |
317 | i2c_dev->add(i2c_dev->type); | 343 | if (i2c_dev->add(i2c_dev->type)) |
344 | ret = -EPROBE_DEFER; | ||
318 | } | 345 | } |
319 | 346 | ||
320 | /* Indicate to dmi_scan that processing is done. */ | 347 | return ret; |
321 | return 1; | ||
322 | } | 348 | } |
323 | 349 | ||
324 | static struct chromeos_laptop samsung_series_5_550 __initdata = { | 350 | static struct chromeos_laptop samsung_series_5_550 = { |
325 | .i2c_peripherals = { | 351 | .i2c_peripherals = { |
326 | /* Touchpad. */ | 352 | /* Touchpad. */ |
327 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, | 353 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, |
@@ -330,14 +356,14 @@ static struct chromeos_laptop samsung_series_5_550 __initdata = { | |||
330 | }, | 356 | }, |
331 | }; | 357 | }; |
332 | 358 | ||
333 | static struct chromeos_laptop samsung_series_5 __initdata = { | 359 | static struct chromeos_laptop samsung_series_5 = { |
334 | .i2c_peripherals = { | 360 | .i2c_peripherals = { |
335 | /* Light Sensor. */ | 361 | /* Light Sensor. */ |
336 | { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS }, | 362 | { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS }, |
337 | }, | 363 | }, |
338 | }; | 364 | }; |
339 | 365 | ||
340 | static struct chromeos_laptop chromebook_pixel __initdata = { | 366 | static struct chromeos_laptop chromebook_pixel = { |
341 | .i2c_peripherals = { | 367 | .i2c_peripherals = { |
342 | /* Touch Screen. */ | 368 | /* Touch Screen. */ |
343 | { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL }, | 369 | { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL }, |
@@ -348,28 +374,28 @@ static struct chromeos_laptop chromebook_pixel __initdata = { | |||
348 | }, | 374 | }, |
349 | }; | 375 | }; |
350 | 376 | ||
351 | static struct chromeos_laptop acer_c7_chromebook __initdata = { | 377 | static struct chromeos_laptop acer_c7_chromebook = { |
352 | .i2c_peripherals = { | 378 | .i2c_peripherals = { |
353 | /* Touchpad. */ | 379 | /* Touchpad. */ |
354 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, | 380 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, |
355 | }, | 381 | }, |
356 | }; | 382 | }; |
357 | 383 | ||
358 | static struct chromeos_laptop acer_ac700 __initdata = { | 384 | static struct chromeos_laptop acer_ac700 = { |
359 | .i2c_peripherals = { | 385 | .i2c_peripherals = { |
360 | /* Light Sensor. */ | 386 | /* Light Sensor. */ |
361 | { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, | 387 | { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, |
362 | }, | 388 | }, |
363 | }; | 389 | }; |
364 | 390 | ||
365 | static struct chromeos_laptop hp_pavilion_14_chromebook __initdata = { | 391 | static struct chromeos_laptop hp_pavilion_14_chromebook = { |
366 | .i2c_peripherals = { | 392 | .i2c_peripherals = { |
367 | /* Touchpad. */ | 393 | /* Touchpad. */ |
368 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, | 394 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, |
369 | }, | 395 | }, |
370 | }; | 396 | }; |
371 | 397 | ||
372 | static struct chromeos_laptop cr48 __initdata = { | 398 | static struct chromeos_laptop cr48 = { |
373 | .i2c_peripherals = { | 399 | .i2c_peripherals = { |
374 | /* Light Sensor. */ | 400 | /* Light Sensor. */ |
375 | { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, | 401 | { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, |
@@ -377,7 +403,7 @@ static struct chromeos_laptop cr48 __initdata = { | |||
377 | }; | 403 | }; |
378 | 404 | ||
379 | #define _CBDD(board_) \ | 405 | #define _CBDD(board_) \ |
380 | .callback = &chromeos_laptop_add_peripherals, \ | 406 | .callback = chromeos_laptop_dmi_matched, \ |
381 | .driver_data = (void *)&board_ | 407 | .driver_data = (void *)&board_ |
382 | 408 | ||
383 | static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = { | 409 | static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = { |
@@ -436,13 +462,45 @@ static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = { | |||
436 | }; | 462 | }; |
437 | MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); | 463 | MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); |
438 | 464 | ||
465 | static struct platform_device *cros_platform_device; | ||
466 | |||
467 | static struct platform_driver cros_platform_driver = { | ||
468 | .driver = { | ||
469 | .name = "chromeos_laptop", | ||
470 | .owner = THIS_MODULE, | ||
471 | }, | ||
472 | .probe = chromeos_laptop_probe, | ||
473 | }; | ||
474 | |||
439 | static int __init chromeos_laptop_init(void) | 475 | static int __init chromeos_laptop_init(void) |
440 | { | 476 | { |
477 | int ret; | ||
441 | if (!dmi_check_system(chromeos_laptop_dmi_table)) { | 478 | if (!dmi_check_system(chromeos_laptop_dmi_table)) { |
442 | pr_debug("%s unsupported system.\n", __func__); | 479 | pr_debug("%s unsupported system.\n", __func__); |
443 | return -ENODEV; | 480 | return -ENODEV; |
444 | } | 481 | } |
482 | |||
483 | ret = platform_driver_register(&cros_platform_driver); | ||
484 | if (ret) | ||
485 | return ret; | ||
486 | |||
487 | cros_platform_device = platform_device_alloc("chromeos_laptop", -1); | ||
488 | if (!cros_platform_device) { | ||
489 | ret = -ENOMEM; | ||
490 | goto fail_platform_device1; | ||
491 | } | ||
492 | |||
493 | ret = platform_device_add(cros_platform_device); | ||
494 | if (ret) | ||
495 | goto fail_platform_device2; | ||
496 | |||
445 | return 0; | 497 | return 0; |
498 | |||
499 | fail_platform_device2: | ||
500 | platform_device_put(cros_platform_device); | ||
501 | fail_platform_device1: | ||
502 | platform_driver_unregister(&cros_platform_driver); | ||
503 | return ret; | ||
446 | } | 504 | } |
447 | 505 | ||
448 | static void __exit chromeos_laptop_exit(void) | 506 | static void __exit chromeos_laptop_exit(void) |