On Thu, Oct 25, 2012 at 10:21 PM, Benson Leung <ble...@chromium.org> wrote: > This adds the chromeos_laptop driver. It supports > the Cypress APA SMBUS touchpad as well as the isl29018 i2c ambient > light sensor on the Samsung Series 5 550 Chromebook. > > Signed-off-by: Benson Leung <ble...@chromium.org> > Reviewed-by: Olof Johansson <o...@lixom.net> > --- > Version history : > v2 : * Added MODULE_DEVICE_TABLE for the dmi table. > * Made __init and __initdata position consistent across this file. > * Made prefix static const char * > * Made strncmp expressions more explicit > * Added an additional match for DMI_SYS_VENDOR for Samsung Lumpy. > v1 : Initial > --- > drivers/platform/x86/Kconfig | 11 ++ > drivers/platform/x86/Makefile | 1 + > drivers/platform/x86/chromeos_laptop.c | 205 > ++++++++++++++++++++++++++++++++ > 3 files changed, 217 insertions(+), 0 deletions(-) > create mode 100644 drivers/platform/x86/chromeos_laptop.c > > diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig > index c86bae8..12b8594 100644 > --- a/drivers/platform/x86/Kconfig > +++ b/drivers/platform/x86/Kconfig > @@ -79,6 +79,17 @@ config ASUS_LAPTOP > > If you have an ACPI-compatible ASUS laptop, say Y or M here. > > +config CHROMEOS_LAPTOP > + tristate "Chrome OS Laptop" > + depends on I2C > + depends on DMI > + ---help--- > + This driver instantiates i2c and smbus devices such as > + light sensors and touchpads. > + > + If you have a supported Chromebook, choose Y or M here. > + The module will be called chromeos_laptop. > + > config DELL_LAPTOP > tristate "Dell Laptop Extras (EXPERIMENTAL)" > depends on X86 > diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile > index bf7e4f9..ace2b38 100644 > --- a/drivers/platform/x86/Makefile > +++ b/drivers/platform/x86/Makefile > @@ -50,3 +50,4 @@ obj-$(CONFIG_INTEL_MID_POWER_BUTTON) += > intel_mid_powerbtn.o > obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o > obj-$(CONFIG_SAMSUNG_Q10) += samsung-q10.o > obj-$(CONFIG_APPLE_GMUX) += apple-gmux.o > +obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o > diff --git a/drivers/platform/x86/chromeos_laptop.c > b/drivers/platform/x86/chromeos_laptop.c > new file mode 100644 > index 0000000..a8329c3 > --- /dev/null > +++ b/drivers/platform/x86/chromeos_laptop.c > @@ -0,0 +1,205 @@ > +/* > + * chromeos_laptop.c - Driver to instantiate Chromebook i2c/smbus devices. > + * > + * Author : Benson Leung <ble...@chromium.org> > + * > + * Copyright (C) 2012 Google, Inc. > + * > + * This program is free software; you can redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; either version 2 of the License, or > + * (at your option) any later version. > + * > + * This program is distributed in the hope that it will be useful, > + * but WITHOUT ANY WARRANTY; without even the implied warranty of > + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > + * GNU General Public License for more details. > + * > + * You should have received a copy of the GNU General Public License > + * along with this program; if not, write to the Free Software > + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA > + * > + */ > + > +#include <linux/dmi.h> > +#include <linux/i2c.h> > +#include <linux/module.h> > + > +#define CYAPA_TP_I2C_ADDR 0x67 > +#define ISL_ALS_I2C_ADDR 0x44 > + > +static struct i2c_client *als; > +static struct i2c_client *tp; > + > +const char *i2c_adapter_names[] = { > + "SMBus I801 adapter", > +}; > + > +/* Keep this enum consistent with i2c_adapter_names */ > +enum i2c_adapter_type { > + I2C_ADAPTER_SMBUS = 0, > +}; > + > +static struct i2c_board_info __initdata cyapa_device = { > + I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), > + .flags = I2C_CLIENT_WAKE, > +}; > + > +static struct i2c_board_info __initdata isl_als_device = { > + I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), > +}; > + > +static struct i2c_client __init *__add_probed_i2c_device( > + const char *name, > + int bus, > + struct i2c_board_info *info, > + const unsigned short *addrs) > +{ > + const struct dmi_device *dmi_dev; > + const struct dmi_dev_onboard *dev_data; > + struct i2c_adapter *adapter; > + struct i2c_client *client; > + > + if (bus < 0) > + return NULL; > + /* > + * If a name is specified, look for irq platform information stashed > + * in DMI_DEV_TYPE_DEV_ONBOARD by the Chrome OS custom system > firmware. > + */ > + if (name) { > + dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, name, > NULL); > + if (!dmi_dev) { > + pr_err("%s failed to dmi find device %s.\n", > + __func__, > + name); > + return NULL; > + } > + dev_data = (struct dmi_dev_onboard *)dmi_dev->device_data; > + if (!dev_data) { > + pr_err("%s failed to get data from dmi for %s.\n", > + __func__, name); > + return NULL; > + } > + info->irq = dev_data->instance; > + } > + > + adapter = i2c_get_adapter(bus); > + if (!adapter) { > + pr_err("%s failed to get i2c adapter %d.\n", __func__, bus); > + return NULL; > + } > + > + /* add the i2c device */ > + client = i2c_new_probed_device(adapter, info, addrs, NULL); > + if (!client) > + pr_err("%s failed to register device %d-%02x\n", > + __func__, bus, info->addr); > + else > + pr_debug("%s added i2c device %d-%02x\n", > + __func__, bus, info->addr); > + > + i2c_put_adapter(adapter); > + return client; > +} > + > +static int __init __find_i2c_adap(struct device *dev, void *data) > +{ > + const char *name = data; > + static const char *prefix = "i2c-"; > + struct i2c_adapter *adapter; > + if (strncmp(dev_name(dev), prefix, strlen(prefix)) != 0) > + return 0; > + adapter = to_i2c_adapter(dev); > + return (strncmp(adapter->name, name, strlen(name)) == 0); > +} > + > +static int __init find_i2c_adapter_num(enum i2c_adapter_type type) > +{ > + struct device *dev = NULL; > + struct i2c_adapter *adapter; > + const char *name = i2c_adapter_names[type]; > + /* find the adapter by name */ > + dev = bus_find_device(&i2c_bus_type, NULL, (void *)name, > + __find_i2c_adap); > + if (!dev) { > + pr_err("%s: i2c adapter %s not found on system.\n", __func__, > + name); > + return -ENODEV; > + } > + adapter = to_i2c_adapter(dev); > + return adapter->nr; > +} > + > +/* > + * Probes for a device at a single address, the one provided by > + * info->addr. > + * Returns NULL if no device found. > + */ > +static struct i2c_client __init *add_smbus_device(const char *name, > + struct i2c_board_info *info) > +{ > + const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END }; > + return __add_probed_i2c_device(name, > + > find_i2c_adapter_num(I2C_ADAPTER_SMBUS), > + info, > + addr_list); > +} > + > +static int __init setup_lumpy_tp(const struct dmi_system_id *id) > +{ > + /* add cyapa touchpad on smbus */ > + tp = add_smbus_device("trackpad", &cyapa_device); > + return 0; > +} > + > +static int __init setup_isl29018_als(const struct dmi_system_id *id) > +{ > + /* add isl29018 light sensor */ > + als = add_smbus_device("lightsensor", &isl_als_device); > + return 0; > +} > + > +static struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = { > + { > + .ident = "Samsung Series 5 550 - Touchpad", > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"), > + DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"), > + }, > + .callback = setup_lumpy_tp, > + }, > + { > + .ident = "Samsung Series 5 550 - Light Sensor", > + .matches = { > + DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"), > + DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"), > + }, > + .callback = setup_isl29018_als, > + }, > + { } > +}; > +MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); > + > +static int __init chromeos_laptop_init(void) > +{ > + if (!dmi_check_system(chromeos_laptop_dmi_table)) { > + pr_debug("%s unsupported system.\n", __func__); > + return -ENODEV; > + } > + return 0; > +} > + > +static void __exit chromeos_laptop_exit(void) > +{ > + if (als) > + i2c_unregister_device(als); > + if (tp) > + i2c_unregister_device(tp); > +} > + > +module_init(chromeos_laptop_init); > +module_exit(chromeos_laptop_exit); > + > +MODULE_DESCRIPTION("Chrome OS Laptop driver"); > +MODULE_AUTHOR("Benson Leung <ble...@chromium.org>"); > +MODULE_LICENSE("GPL"); > -- > 1.7.7.3
Looks better, but I'm curious, what is the final purpose of this driver ? What ABI will be exposed, who will use it ? If it is going to be bigger, it may be a good idea to convert it to a real platform driver (platform_drivers/platform_device stuff). Thanks, -- Corentin Chary http://xf.iksaif.net -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/