2 * chromeos_laptop.c - Driver to instantiate Chromebook i2c/smbus and platform
5 * Copyright (C) 2012 Google, Inc.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 #include <linux/dmi.h>
24 #include <linux/i2c.h>
25 #include <linux/i2c/atmel_mxt_ts.h>
26 #include <linux/interrupt.h>
27 #include <linux/module.h>
28 #include <linux/platform_device.h>
30 #define ATMEL_TP_I2C_ADDR 0x4b
31 #define ATMEL_TP_I2C_BL_ADDR 0x25
32 #define ATMEL_TS_I2C_ADDR 0x4a
33 #define ATMEL_TS_I2C_BL_ADDR 0x26
34 #define CYAPA_TP_I2C_ADDR 0x67
35 #define ISL_ALS_I2C_ADDR 0x44
36 #define TAOS_ALS_I2C_ADDR 0x29
38 static struct i2c_client *als;
39 static struct i2c_client *tp;
40 static struct i2c_client *ts;
42 const char *i2c_adapter_names[] = {
48 /* Keep this enum consistent with i2c_adapter_names */
49 enum i2c_adapter_type {
50 I2C_ADAPTER_SMBUS = 0,
55 static struct i2c_board_info __initdata cyapa_device = {
56 I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
57 .flags = I2C_CLIENT_WAKE,
60 static struct i2c_board_info __initdata isl_als_device = {
61 I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
64 static struct i2c_board_info __initdata tsl2583_als_device = {
65 I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
68 static struct i2c_board_info __initdata tsl2563_als_device = {
69 I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
72 static const u8 atmel_224e_tp_config_data[] = {
73 /* MXT_GEN_COMMAND(6) */
74 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
75 /* MXT_GEN_POWERCONFIG(7) */
77 /* MXT_GEN_ACQUIRE(8) */
78 0x06, 0x00, 0x14, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
79 /* MXT_TOUCH_MULTI(9) */
80 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
81 0x00, 0x02, 0x01, 0x00, 0x0a, 0x03, 0x03, 0x0a, 0x00, 0x00,
82 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
83 0x20, 0x00, 0x37, 0x37, 0x00,
84 /* MXT_TOUCH_KEYARRAY(15) */
85 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
87 /* MXT_SPT_COMMSCONFIG(18) */
89 /* MXT_SPT_GPIOPWM(19) */
90 0x03, 0xDF, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
91 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
92 /* MXT_TOUCH_PROXIMITY(23) */
93 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
94 0x00, 0x00, 0x00, 0x00, 0x00,
95 /* MXT_SPT_SELFTEST(25) */
96 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
97 0x00, 0x00, 0x00, 0x00,
98 /* MXT_PROCI_GRIPSUPPRESSION(40) */
99 0x00, 0x00, 0x00, 0x00, 0x00,
100 /* MXT_PROCI_TOUCHSUPPRESSION(42) */
101 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
102 /* MXT_SPT_CTECONFIG(46) */
103 0x00, 0x02, 0x0a, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00,
104 /* MXT_PROCI_STYLUS(47) */
105 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
106 /* MXT_PROCG_NOISESUPPRESSION(48) */
107 0x01, 0x00, 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
108 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
109 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
110 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
111 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
112 0x00, 0x00, 0x00, 0x00
115 static struct mxt_platform_data atmel_224e_tp_platform_data = {
120 .blen = 0x20, /* Gain setting is in upper 4 bits */
122 .voltage = 0, /* 3.3V */
123 .orient = MXT_HORIZONTAL_FLIP,
124 .irqflags = IRQF_TRIGGER_FALLING,
125 .config = atmel_224e_tp_config_data,
126 .config_length = sizeof(atmel_224e_tp_config_data),
129 static struct i2c_board_info __initdata atmel_224e_tp_device = {
130 I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR),
131 .platform_data = &atmel_224e_tp_platform_data,
132 .flags = I2C_CLIENT_WAKE,
135 static struct i2c_board_info __initdata atmel_224s_tp_device = {
136 I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR),
137 .platform_data = NULL,
138 .flags = I2C_CLIENT_WAKE,
141 static struct i2c_board_info __initdata atmel_1664s_device = {
142 I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR),
143 .platform_data = NULL,
144 .flags = I2C_CLIENT_WAKE,
147 static __init struct i2c_client *__add_probed_i2c_device(
150 struct i2c_board_info *info,
151 const unsigned short *addrs)
153 const struct dmi_device *dmi_dev;
154 const struct dmi_dev_onboard *dev_data;
155 struct i2c_adapter *adapter;
156 struct i2c_client *client;
161 * If a name is specified, look for irq platform information stashed
162 * in DMI_DEV_TYPE_DEV_ONBOARD.
165 dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, name, NULL);
167 pr_err("%s failed to dmi find device %s.\n",
172 dev_data = (struct dmi_dev_onboard *)dmi_dev->device_data;
174 pr_err("%s failed to get data from dmi for %s.\n",
178 info->irq = dev_data->instance;
181 adapter = i2c_get_adapter(bus);
183 pr_err("%s failed to get i2c adapter %d.\n", __func__, bus);
187 /* add the i2c device */
188 client = i2c_new_probed_device(adapter, info, addrs, NULL);
190 pr_err("%s failed to register device %d-%02x\n",
191 __func__, bus, info->addr);
193 pr_debug("%s added i2c device %d-%02x\n",
194 __func__, bus, info->addr);
196 i2c_put_adapter(adapter);
200 static int __init __find_i2c_adap(struct device *dev, void *data)
202 const char *name = data;
203 const char *prefix = "i2c-";
204 struct i2c_adapter *adapter;
205 if (strncmp(dev_name(dev), prefix, strlen(prefix)))
207 adapter = to_i2c_adapter(dev);
208 return !strncmp(adapter->name, name, strlen(name));
211 static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
213 struct device *dev = NULL;
214 struct i2c_adapter *adapter;
215 const char *name = i2c_adapter_names[type];
216 /* find the adapter by name */
217 dev = bus_find_device(&i2c_bus_type, NULL, (void *)name,
220 pr_err("%s: i2c adapter %s not found on system.\n", __func__,
224 adapter = to_i2c_adapter(dev);
229 * Takes a list of addresses in addrs as such :
230 * { addr1, ... , addrn, I2C_CLIENT_END };
231 * chromeos_laptop_add_probed_i2c_device will use i2c_new_probed_device
232 * and probe for devices at all of the addresses listed.
233 * Returns NULL if no devices found.
234 * See Documentation/i2c/instantiating-devices for more information.
236 static __init struct i2c_client *chromeos_laptop_add_probed_i2c_device(
238 enum i2c_adapter_type type,
239 struct i2c_board_info *info,
240 const unsigned short *addrs)
242 return __add_probed_i2c_device(name,
243 find_i2c_adapter_num(type),
249 * Probes for a device at a single address, the one provided by
251 * Returns NULL if no device found.
253 static __init struct i2c_client *chromeos_laptop_add_i2c_device(
255 enum i2c_adapter_type type,
256 struct i2c_board_info *info)
258 const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
259 return __add_probed_i2c_device(name,
260 find_i2c_adapter_num(type),
265 static __init struct i2c_client *add_smbus_device(const char *name,
266 struct i2c_board_info *info)
268 return chromeos_laptop_add_i2c_device(name, I2C_ADAPTER_SMBUS, info);
271 static int __init setup_atmel_1664s_ts(const struct dmi_system_id *id)
273 const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR,
277 ts = chromeos_laptop_add_probed_i2c_device("touchscreen",
284 static int __init setup_cyapa_smbus_tp(const struct dmi_system_id *id)
286 /* add cyapa touchpad */
287 tp = add_smbus_device("trackpad", &cyapa_device);
291 static int __init setup_atmel_224s_tp(const struct dmi_system_id *id)
293 const unsigned short atmel_addr_list[] = { ATMEL_TP_I2C_BL_ADDR,
297 /* add atmel mxt touchpad */
298 tp = chromeos_laptop_add_probed_i2c_device("trackpad",
300 &atmel_224s_tp_device,
305 static int __init setup_lumpy_tp(const struct dmi_system_id *id)
307 /* first try cyapa touchpad on smbus */
308 setup_cyapa_smbus_tp(id);
312 /* then try atmel mxt touchpad */
313 tp = chromeos_laptop_add_i2c_device("trackpad",
315 &atmel_224e_tp_device);
319 static int __init setup_isl29018_als(const struct dmi_system_id *id)
321 /* add isl29018 light sensor */
322 als = add_smbus_device("lightsensor", &isl_als_device);
326 static int __init setup_isl29023_als(const struct dmi_system_id *id)
328 /* add isl29023 light sensor on Panel DDC GMBus */
329 als = chromeos_laptop_add_i2c_device("lightsensor",
335 static int __init setup_tsl2583_als(const struct dmi_system_id *id)
337 /* add tsl2583 light sensor */
338 als = add_smbus_device(NULL, &tsl2583_als_device);
342 static int __init setup_tsl2563_als(const struct dmi_system_id *id)
344 /* add tsl2563 light sensor */
345 als = add_smbus_device(NULL, &tsl2563_als_device);
349 static struct platform_device *kb_backlight_device;
351 static int __init setup_keyboard_backlight(const struct dmi_system_id *id)
353 kb_backlight_device =
354 platform_device_register_simple("chromeos-keyboard-leds",
356 if (IS_ERR(kb_backlight_device)) {
357 pr_warn("Error registering Chrome OS keyboard LEDs.\n");
358 kb_backlight_device = NULL;
363 static const struct __initdata dmi_system_id chromeos_laptop_dmi_table[] = {
365 .ident = "Lumpy - Touchpads",
367 DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
369 .callback = setup_lumpy_tp,
372 .ident = "Chromebook Pixel - Touchscreen",
374 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
376 .callback = setup_atmel_1664s_ts,
379 .ident = "Chromebook Pixel - Touchpad",
381 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
383 .callback = setup_atmel_224s_tp,
386 .ident = "isl29018 - Light Sensor",
388 DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
390 .callback = setup_isl29018_als,
393 .ident = "isl29023 - Light Sensor",
395 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
397 .callback = setup_isl29023_als,
400 .ident = "Parrot - Touchpad",
402 DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
404 .callback = setup_cyapa_smbus_tp,
407 .ident = "Butterfy - Touchpad",
409 DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
411 .callback = setup_cyapa_smbus_tp,
414 .ident = "tsl2583 - Light Sensor",
416 DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
418 .callback = setup_tsl2583_als,
421 .ident = "tsl2563 - Light Sensor",
423 DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
425 .callback = setup_tsl2563_als,
428 .ident = "tsl2563 - Light Sensor",
430 DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
432 .callback = setup_tsl2563_als,
435 .ident = "Chromebook Pixel - Keyboard backlight",
437 DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
439 .callback = setup_keyboard_backlight,
443 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
445 static int __init chromeos_laptop_init(void)
447 if (!dmi_check_system(chromeos_laptop_dmi_table)) {
448 pr_debug("%s unsupported system.\n", __func__);
454 static void __exit chromeos_laptop_exit(void)
457 i2c_unregister_device(als);
459 i2c_unregister_device(tp);
461 i2c_unregister_device(ts);
462 if (kb_backlight_device)
463 platform_device_unregister(kb_backlight_device);
466 module_init(chromeos_laptop_init);
467 module_exit(chromeos_laptop_exit);
469 MODULE_DESCRIPTION("Chrome OS Laptop driver");
470 MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
471 MODULE_LICENSE("GPL");