summaryrefslogtreecommitdiffstats
path: root/drivers/platform
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/platform')
-rw-r--r--drivers/platform/chrome/chromeos_laptop.c476
1 files changed, 264 insertions, 212 deletions
diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index fe83a2a..5c47f45 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -54,13 +54,16 @@ struct i2c_peripheral {
struct i2c_client *client;
};
-#define MAX_I2C_PERIPHERALS 4
-
struct chromeos_laptop {
- struct i2c_peripheral i2c_peripherals[MAX_I2C_PERIPHERALS];
+ /*
+ * Note that we can't mark this pointer as const because
+ * i2c_new_probed_device() changes passed in I2C board info, so.
+ */
+ struct i2c_peripheral *i2c_peripherals;
+ unsigned int num_i2c_peripherals;
};
-static struct chromeos_laptop *cros_laptop;
+static const struct chromeos_laptop *cros_laptop;
static struct i2c_client *
chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter,
@@ -121,13 +124,9 @@ static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
struct i2c_peripheral *i2c_dev;
int i;
- for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
+ for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
i2c_dev = &cros_laptop->i2c_peripherals[i];
- /* No more peripherals */
- if (!i2c_dev->board_info.addr)
- break;
-
/* Skip devices already created */
if (i2c_dev->client)
continue;
@@ -154,7 +153,7 @@ static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
struct i2c_peripheral *i2c_dev;
int i;
- for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
+ for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
i2c_dev = &cros_laptop->i2c_peripherals[i];
if (i2c_dev->client == client)
@@ -186,41 +185,45 @@ static struct notifier_block chromeos_laptop_i2c_notifier = {
.notifier_call = chromeos_laptop_i2c_notifier_call,
};
-static struct chromeos_laptop samsung_series_5_550 = {
- .i2c_peripherals = {
- /* Touchpad. */
- {
- .board_info = {
- I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_SMBUS,
+#define DECLARE_CROS_LAPTOP(_name) \
+static const struct chromeos_laptop _name __initconst = { \
+ .i2c_peripherals = _name##_peripherals, \
+ .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \
+}
+
+static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = {
+ /* Touchpad. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
- /* Light Sensor. */
- {
- .board_info = {
- I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
- },
- .dmi_name = "lightsensor",
- .type = I2C_ADAPTER_SMBUS,
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_SMBUS,
+ },
+ /* Light Sensor. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
},
+ .dmi_name = "lightsensor",
+ .type = I2C_ADAPTER_SMBUS,
},
};
+DECLARE_CROS_LAPTOP(samsung_series_5_550);
-static struct chromeos_laptop samsung_series_5 = {
- .i2c_peripherals = {
- /* Light Sensor. */
- {
- .board_info = {
- I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
- },
- .type = I2C_ADAPTER_SMBUS,
+static struct i2c_peripheral samsung_series_5_peripherals[] __initdata = {
+ /* Light Sensor. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
},
+ .type = I2C_ADAPTER_SMBUS,
},
};
+DECLARE_CROS_LAPTOP(samsung_series_5);
-static int chromebook_pixel_tp_keys[] = {
+static const int chromebook_pixel_tp_keys[] __initconst = {
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
@@ -229,199 +232,192 @@ static int chromebook_pixel_tp_keys[] = {
BTN_LEFT
};
-static const struct property_entry chromebook_pixel_trackpad_props[] = {
+static const struct property_entry
+chromebook_pixel_trackpad_props[] __initconst = {
PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
{ }
};
-static struct chromeos_laptop chromebook_pixel = {
- .i2c_peripherals = {
- /* Touch Screen. */
- {
- .board_info = {
- I2C_BOARD_INFO("atmel_mxt_ts",
- ATMEL_TS_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "touchscreen",
- .irqflags = IRQF_TRIGGER_FALLING,
- .type = I2C_ADAPTER_PANEL,
- .alt_addr = ATMEL_TS_I2C_BL_ADDR,
+static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
+ /* Touch Screen. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("atmel_mxt_ts",
+ ATMEL_TS_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
- /* Touchpad. */
- {
- .board_info = {
- I2C_BOARD_INFO("atmel_mxt_tp",
- ATMEL_TP_I2C_ADDR),
- .properties =
- chromebook_pixel_trackpad_props,
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .irqflags = IRQF_TRIGGER_FALLING,
- .type = I2C_ADAPTER_VGADDC,
- .alt_addr = ATMEL_TP_I2C_BL_ADDR,
+ .dmi_name = "touchscreen",
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .type = I2C_ADAPTER_PANEL,
+ .alt_addr = ATMEL_TS_I2C_BL_ADDR,
+ },
+ /* Touchpad. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("atmel_mxt_tp",
+ ATMEL_TP_I2C_ADDR),
+ .properties =
+ chromebook_pixel_trackpad_props,
+ .flags = I2C_CLIENT_WAKE,
},
- /* Light Sensor. */
- {
- .board_info = {
- I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
- },
- .dmi_name = "lightsensor",
- .type = I2C_ADAPTER_PANEL,
+ .dmi_name = "trackpad",
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .type = I2C_ADAPTER_VGADDC,
+ .alt_addr = ATMEL_TP_I2C_BL_ADDR,
+ },
+ /* Light Sensor. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
},
+ .dmi_name = "lightsensor",
+ .type = I2C_ADAPTER_PANEL,
},
};
+DECLARE_CROS_LAPTOP(chromebook_pixel);
-static struct chromeos_laptop hp_chromebook_14 = {
- .i2c_peripherals = {
- /* Touchpad. */
- {
- .board_info = {
- I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_DESIGNWARE,
+static struct i2c_peripheral hp_chromebook_14_peripherals[] __initdata = {
+ /* Touchpad. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE,
},
};
+DECLARE_CROS_LAPTOP(hp_chromebook_14);
-static struct chromeos_laptop dell_chromebook_11 = {
- .i2c_peripherals = {
- /* Touchpad. */
- {
- .board_info = {
- I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_DESIGNWARE,
+static struct i2c_peripheral dell_chromebook_11_peripherals[] __initdata = {
+ /* Touchpad. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
- /* Elan Touchpad option. */
- {
- .board_info = {
- I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_DESIGNWARE,
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE,
+ },
+ /* Elan Touchpad option. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE,
},
};
+DECLARE_CROS_LAPTOP(dell_chromebook_11);
-static struct chromeos_laptop toshiba_cb35 = {
- .i2c_peripherals = {
- /* Touchpad. */
- {
- .board_info = {
- I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_DESIGNWARE,
+static struct i2c_peripheral toshiba_cb35_peripherals[] __initdata = {
+ /* Touchpad. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE,
},
};
+DECLARE_CROS_LAPTOP(toshiba_cb35);
-static struct chromeos_laptop acer_c7_chromebook = {
- .i2c_peripherals = {
- /* Touchpad. */
- {
- .board_info = {
- I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_SMBUS,
+static struct i2c_peripheral acer_c7_chromebook_peripherals[] __initdata = {
+ /* Touchpad. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_SMBUS,
},
};
+DECLARE_CROS_LAPTOP(acer_c7_chromebook);
-static struct chromeos_laptop acer_ac700 = {
- .i2c_peripherals = {
- /* Light Sensor. */
- {
- .board_info = {
- I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
- },
- .type = I2C_ADAPTER_SMBUS,
+static struct i2c_peripheral acer_ac700_peripherals[] __initdata = {
+ /* Light Sensor. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
},
+ .type = I2C_ADAPTER_SMBUS,
},
};
+DECLARE_CROS_LAPTOP(acer_ac700);
-static struct chromeos_laptop acer_c720 = {
- .i2c_peripherals = {
- /* Touchscreen. */
- {
- .board_info = {
- I2C_BOARD_INFO("atmel_mxt_ts",
- ATMEL_TS_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "touchscreen",
- .irqflags = IRQF_TRIGGER_FALLING,
- .type = I2C_ADAPTER_DESIGNWARE,
- .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
- .alt_addr = ATMEL_TS_I2C_BL_ADDR,
+static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
+ /* Touchscreen. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("atmel_mxt_ts",
+ ATMEL_TS_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
- /* Touchpad. */
- {
- .board_info = {
- I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_DESIGNWARE,
- .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
+ .dmi_name = "touchscreen",
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .type = I2C_ADAPTER_DESIGNWARE,
+ .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
+ .alt_addr = ATMEL_TS_I2C_BL_ADDR,
+ },
+ /* Touchpad. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
- /* Elan Touchpad option. */
- {
- .board_info = {
- I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_DESIGNWARE,
- .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE,
+ .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
+ },
+ /* Elan Touchpad option. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
- /* Light Sensor. */
- {
- .board_info = {
- I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
- },
- .dmi_name = "lightsensor",
- .type = I2C_ADAPTER_DESIGNWARE,
- .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE,
+ .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
+ },
+ /* Light Sensor. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
},
+ .dmi_name = "lightsensor",
+ .type = I2C_ADAPTER_DESIGNWARE,
+ .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
},
};
+DECLARE_CROS_LAPTOP(acer_c720);
-static struct chromeos_laptop hp_pavilion_14_chromebook = {
- .i2c_peripherals = {
- /* Touchpad. */
- {
- .board_info = {
- I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
- },
- .dmi_name = "trackpad",
- .type = I2C_ADAPTER_SMBUS,
+static struct i2c_peripheral
+hp_pavilion_14_chromebook_peripherals[] __initdata = {
+ /* Touchpad. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
},
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_SMBUS,
},
};
+DECLARE_CROS_LAPTOP(hp_pavilion_14_chromebook);
-static struct chromeos_laptop cr48 = {
- .i2c_peripherals = {
- /* Light Sensor. */
- {
- .board_info = {
- I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
- },
- .type = I2C_ADAPTER_SMBUS,
+static struct i2c_peripheral cr48_peripherals[] __initdata = {
+ /* Light Sensor. */
+ {
+ .board_info = {
+ I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
},
+ .type = I2C_ADAPTER_SMBUS,
},
};
+DECLARE_CROS_LAPTOP(cr48);
static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
{
@@ -541,24 +537,14 @@ static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
return dev_data->instance;
}
-static struct chromeos_laptop * __init
-chromeos_laptop_prepare(const struct dmi_system_id *id)
+static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev)
{
- struct i2c_peripheral *i2c_dev;
int irq;
- int i;
-
- cros_laptop = (void *)id->driver_data;
-
- for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
- i2c_dev = &cros_laptop->i2c_peripherals[i];
-
- if (!i2c_dev->dmi_name)
- continue;
+ if (i2c_dev->dmi_name) {
irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
if (irq < 0)
- return ERR_PTR(irq);
+ return irq;
i2c_dev->irq_resource = (struct resource)
DEFINE_RES_NAMED(irq, 1, NULL,
@@ -567,9 +553,87 @@ chromeos_laptop_prepare(const struct dmi_system_id *id)
i2c_dev->board_info.num_resources = 1;
}
+ return 0;
+}
+
+static struct chromeos_laptop * __init
+chromeos_laptop_prepare(const struct chromeos_laptop *src)
+{
+ struct chromeos_laptop *cros_laptop;
+ struct i2c_peripheral *i2c_dev;
+ struct i2c_board_info *info;
+ int error;
+ int i;
+
+ cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
+ if (!cros_laptop)
+ return ERR_PTR(-ENOMEM);
+
+ cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals,
+ src->num_i2c_peripherals *
+ sizeof(*src->i2c_peripherals),
+ GFP_KERNEL);
+ if (!cros_laptop->i2c_peripherals) {
+ error = -ENOMEM;
+ goto err_free_cros_laptop;
+ }
+
+ cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals;
+
+ for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
+ i2c_dev = &cros_laptop->i2c_peripherals[i];
+ info = &i2c_dev->board_info;
+
+ error = chromeos_laptop_setup_irq(i2c_dev);
+ if (error)
+ goto err_destroy_cros_peripherals;
+
+ /* We need to deep-copy properties */
+ if (info->properties) {
+ info->properties =
+ property_entries_dup(info->properties);
+ if (IS_ERR(info->properties)) {
+ error = PTR_ERR(info->properties);
+ goto err_destroy_cros_peripherals;
+ }
+ }
+ }
+
return cros_laptop;
+
+err_destroy_cros_peripherals:
+ while (--i >= 0) {
+ i2c_dev = &cros_laptop->i2c_peripherals[i];
+ info = &i2c_dev->board_info;
+ if (info->properties)
+ property_entries_free(info->properties);
+ }
+ kfree(cros_laptop->i2c_peripherals);
+err_free_cros_laptop:
+ kfree(cros_laptop);
+ return ERR_PTR(error);
}
+static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
+{
+ struct i2c_peripheral *i2c_dev;
+ struct i2c_board_info *info;
+ int i;
+
+ for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
+ i2c_dev = &cros_laptop->i2c_peripherals[i];
+ info = &i2c_dev->board_info;
+
+ if (i2c_dev->client)
+ i2c_unregister_device(i2c_dev->client);
+
+ if (info->properties)
+ property_entries_free(info->properties);
+ }
+
+ kfree(cros_laptop->i2c_peripherals);
+ kfree(cros_laptop);
+}
static int __init chromeos_laptop_init(void)
{
@@ -584,7 +648,7 @@ static int __init chromeos_laptop_init(void)
pr_debug("DMI Matched %s\n", dmi_id->ident);
- cros_laptop = chromeos_laptop_prepare(dmi_id->driver_data);
+ cros_laptop = chromeos_laptop_prepare((void *)dmi_id->driver_data);
if (IS_ERR(cros_laptop))
return PTR_ERR(cros_laptop);
@@ -592,6 +656,7 @@ static int __init chromeos_laptop_init(void)
&chromeos_laptop_i2c_notifier);
if (error) {
pr_err("failed to register i2c bus notifier: %d\n", error);
+ chromeos_laptop_destroy(cros_laptop);
return error;
}
@@ -606,21 +671,8 @@ static int __init chromeos_laptop_init(void)
static void __exit chromeos_laptop_exit(void)
{
- struct i2c_peripheral *i2c_dev;
- int i;
-
bus_unregister_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier);
-
- for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
- i2c_dev = &cros_laptop->i2c_peripherals[i];
-
- /* No more peripherals */
- if (!i2c_dev->board_info.type)
- break;
-
- if (i2c_dev->client)
- i2c_unregister_device(i2c_dev->client);
- }
+ chromeos_laptop_destroy(cros_laptop);
}
module_init(chromeos_laptop_init);
OpenPOWER on IntegriCloud