aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
authorBenson Leung <bleung@chromium.org>2013-10-20 23:58:25 -0400
committerOlof Johansson <olof@lixom.net>2013-11-25 15:51:09 -0500
commit9ad3692458c387eb9537da73b2b75841ed7acdaf (patch)
treef9504a0bfb1938ab6d38be5d914e8cbbcfe8a5b6 /drivers/platform
parentec199dd57ef71858b53828283ac495ed82164933 (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.c144
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
56struct i2c_peripheral { 57struct 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
67static struct i2c_board_info __initdata cyapa_device = { 68static struct chromeos_laptop *cros_laptop;
69
70static 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
72static struct i2c_board_info __initdata isl_als_device = { 75static 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
76static struct i2c_board_info __initdata tsl2583_als_device = { 79static 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
80static struct i2c_board_info __initdata tsl2563_als_device = { 83static 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
103static struct i2c_board_info __initdata atmel_224s_tp_device = { 106static 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
124static struct i2c_board_info __initdata atmel_1664s_device = { 127static 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
130static struct i2c_client __init *__add_probed_i2c_device( 133static 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
183static int __init __find_i2c_adap(struct device *dev, void *data) 186static 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
194static int __init find_i2c_adapter_num(enum i2c_adapter_type type) 197static 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 */
219static __init struct i2c_client *add_probed_i2c_device( 223static 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 */
236static __init struct i2c_client *add_i2c_device(const char *name, 240static 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
247static int __init setup_cyapa_tp(enum i2c_adapter_type type) 251static 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
254static int __init setup_atmel_224s_tp(enum i2c_adapter_type type) 261static 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
266static int __init setup_atmel_1664s_ts(enum i2c_adapter_type type) 275static 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
278static int __init setup_isl29018_als(enum i2c_adapter_type type) 289static 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
285static int __init setup_tsl2583_als(enum i2c_adapter_type type) 299static 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
292static int __init setup_tsl2563_als(enum i2c_adapter_type type) 309static 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
299static int __init 319static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
300chromeos_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
328static 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
324static struct chromeos_laptop samsung_series_5_550 __initdata = { 350static 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
333static struct chromeos_laptop samsung_series_5 __initdata = { 359static 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
340static struct chromeos_laptop chromebook_pixel __initdata = { 366static 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
351static struct chromeos_laptop acer_c7_chromebook __initdata = { 377static 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
358static struct chromeos_laptop acer_ac700 __initdata = { 384static 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
365static struct chromeos_laptop hp_pavilion_14_chromebook __initdata = { 391static 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
372static struct chromeos_laptop cr48 __initdata = { 398static 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
383static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = { 409static 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};
437MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); 463MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
438 464
465static struct platform_device *cros_platform_device;
466
467static struct platform_driver cros_platform_driver = {
468 .driver = {
469 .name = "chromeos_laptop",
470 .owner = THIS_MODULE,
471 },
472 .probe = chromeos_laptop_probe,
473};
474
439static int __init chromeos_laptop_init(void) 475static 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
499fail_platform_device2:
500 platform_device_put(cros_platform_device);
501fail_platform_device1:
502 platform_driver_unregister(&cros_platform_driver);
503 return ret;
446} 504}
447 505
448static void __exit chromeos_laptop_exit(void) 506static void __exit chromeos_laptop_exit(void)