[PATCH v2 08/14] platform/chrome: chromeos_laptop - rework i2c peripherals initialization

From: Dmitry Torokhov
Date: Tue Mar 20 2018 - 18:32:49 EST


Instead of having separate setup() functions responsible for instantiating
i2c client for each peripheral, let's generalize the behavior and use
common code for instantiating all i2c peripherals.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@xxxxxxxxx>
---
drivers/platform/chrome/chromeos_laptop.c | 467 +++++++++++-----------
1 file changed, 235 insertions(+), 232 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 96e962ff38e87..2a81ae4c15c93 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -25,10 +25,6 @@

#define MAX_I2C_DEVICE_DEFERRALS 5

-static struct i2c_client *als;
-static struct i2c_client *tp;
-static struct i2c_client *ts;
-
static const char *i2c_adapter_names[] = {
"SMBus I801 adapter",
"i915 gmbus vga",
@@ -50,12 +46,17 @@ enum i2c_peripheral_state {
UNPROBED = 0,
PROBED,
TIMEDOUT,
+ FAILED,
};

struct i2c_peripheral {
- int (*add)(enum i2c_adapter_type type);
+ struct i2c_board_info board_info;
+ unsigned short alt_addr;
+ const char *dmi_name;
enum i2c_adapter_type type;
+
enum i2c_peripheral_state state;
+ struct i2c_client *client;
int tries;
};

@@ -67,59 +68,6 @@ struct chromeos_laptop {

static struct chromeos_laptop *cros_laptop;

-static struct i2c_board_info cyapa_device = {
- I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
-};
-
-static struct i2c_board_info elantech_device = {
- I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
- .flags = I2C_CLIENT_WAKE,
-};
-
-static struct i2c_board_info isl_als_device = {
- I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
-};
-
-static struct i2c_board_info tsl2583_als_device = {
- I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
-};
-
-static struct i2c_board_info tsl2563_als_device = {
- I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
-};
-
-static int mxt_t19_keys[] = {
- KEY_RESERVED,
- KEY_RESERVED,
- KEY_RESERVED,
- KEY_RESERVED,
- KEY_RESERVED,
- BTN_LEFT
-};
-
-static struct mxt_platform_data atmel_224s_tp_platform_data = {
- .irqflags = IRQF_TRIGGER_FALLING,
- .t19_num_keys = ARRAY_SIZE(mxt_t19_keys),
- .t19_keymap = mxt_t19_keys,
-};
-
-static struct i2c_board_info atmel_224s_tp_device = {
- I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR),
- .platform_data = &atmel_224s_tp_platform_data,
- .flags = I2C_CLIENT_WAKE,
-};
-
-static struct mxt_platform_data atmel_1664s_platform_data = {
- .irqflags = IRQF_TRIGGER_FALLING,
-};
-
-static struct i2c_board_info atmel_1664s_device = {
- I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR),
- .platform_data = &atmel_1664s_platform_data,
- .flags = I2C_CLIENT_WAKE,
-};
-
static int chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
{
const struct dmi_device *dmi_dev;
@@ -140,29 +88,15 @@ static int chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
return dev_data->instance;
}

-static struct i2c_client *__add_probed_i2c_device(
- const char *name,
- int bus,
- struct i2c_board_info *info,
- const unsigned short *alt_addr_list)
+static struct i2c_client *
+chromes_laptop_instantiate_i2c_device(int bus,
+ struct i2c_board_info *info,
+ unsigned short alt_addr)
{
struct i2c_adapter *adapter;
struct i2c_client *client = NULL;
const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };

- 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) {
- info->irq = chromeos_laptop_get_irq_from_dmi(name);
- if (info->irq < 0)
- return NULL;
- }
-
adapter = i2c_get_adapter(bus);
if (!adapter) {
pr_err("failed to get i2c adapter %d\n", bus);
@@ -175,10 +109,13 @@ static struct i2c_client *__add_probed_i2c_device(
* structure gets assigned primary address.
*/
client = i2c_new_probed_device(adapter, info, addr_list, NULL);
- if (!client && alt_addr_list) {
+ if (!client && alt_addr) {
struct i2c_board_info dummy_info = {
I2C_BOARD_INFO("dummy", info->addr),
};
+ const unsigned short alt_addr_list[] = {
+ alt_addr, I2C_CLIENT_END
+ };
struct i2c_client *dummy;

dummy = i2c_new_probed_device(adapter, &dummy_info,
@@ -244,115 +181,53 @@ static int find_i2c_adapter_num(enum i2c_adapter_type type)
return adapter->nr;
}

-/*
- * Takes a list of addresses in addrs as such :
- * { addr1, ... , addrn, I2C_CLIENT_END };
- * add_probed_i2c_device will use i2c_new_probed_device
- * and probe for devices at all of the addresses listed.
- * Returns NULL if no devices found.
- * See Documentation/i2c/instantiating-devices for more information.
- */
-static struct i2c_client *add_probed_i2c_device(
- const char *name,
- enum i2c_adapter_type type,
- struct i2c_board_info *info,
- const unsigned short *addrs)
+static int chromeos_laptop_add_peripheral(struct i2c_peripheral *i2c_dev)
{
- return __add_probed_i2c_device(name,
- find_i2c_adapter_num(type),
- info,
- addrs);
-}
+ struct i2c_client *client;
+ int bus;
+ int irq;

-/*
- * Probes for a device at a single address, the one provided by
- * info->addr.
- * Returns NULL if no device found.
- */
-static struct i2c_client *add_i2c_device(const char *name,
- enum i2c_adapter_type type,
- struct i2c_board_info *info)
-{
- return __add_probed_i2c_device(name,
- find_i2c_adapter_num(type),
- info,
- NULL);
-}
-
-static int setup_cyapa_tp(enum i2c_adapter_type type)
-{
- if (tp)
- return 0;
-
- /* add cyapa touchpad */
- tp = add_i2c_device("trackpad", type, &cyapa_device);
- return (!tp) ? -EAGAIN : 0;
-}
-
-static int setup_atmel_224s_tp(enum i2c_adapter_type type)
-{
- const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR,
- I2C_CLIENT_END };
- if (tp)
- return 0;
-
- /* add atmel mxt touchpad */
- tp = add_probed_i2c_device("trackpad", type,
- &atmel_224s_tp_device, addr_list);
- return (!tp) ? -EAGAIN : 0;
-}
-
-static int setup_elantech_tp(enum i2c_adapter_type type)
-{
- if (tp)
- return 0;
-
- /* add elantech touchpad */
- tp = add_i2c_device("trackpad", type, &elantech_device);
- return (!tp) ? -EAGAIN : 0;
-}
-
-static int setup_atmel_1664s_ts(enum i2c_adapter_type type)
-{
- const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR,
- I2C_CLIENT_END };
- if (ts)
- return 0;
-
- /* add atmel mxt touch device */
- ts = add_probed_i2c_device("touchscreen", type,
- &atmel_1664s_device, addr_list);
- return (!ts) ? -EAGAIN : 0;
-}
-
-static int setup_isl29018_als(enum i2c_adapter_type type)
-{
- if (als)
- return 0;
+ /*
+ * Check that the i2c adapter is present.
+ * -EPROBE_DEFER if missing as the adapter may appear much
+ * later.
+ */
+ bus = find_i2c_adapter_num(i2c_dev->type);
+ if (bus < 0)
+ return bus == -ENODEV ? -EPROBE_DEFER : bus;

- /* add isl29018 light sensor */
- als = add_i2c_device("lightsensor", type, &isl_als_device);
- return (!als) ? -EAGAIN : 0;
-}
+ if (i2c_dev->dmi_name) {
+ irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
+ if (irq < 0) {
+ i2c_dev->state = FAILED;
+ return irq;
+ }

-static int setup_tsl2583_als(enum i2c_adapter_type type)
-{
- if (als)
- return 0;
+ i2c_dev->board_info.irq = irq;
+ }

- /* add tsl2583 light sensor */
- als = add_i2c_device(NULL, type, &tsl2583_als_device);
- return (!als) ? -EAGAIN : 0;
-}
+ client = chromes_laptop_instantiate_i2c_device(bus,
+ &i2c_dev->board_info,
+ i2c_dev->alt_addr);
+ if (!client) {
+ /*
+ * Set -EPROBE_DEFER a limited num of times
+ * if device is not successfully added.
+ */
+ if (++i2c_dev->tries < MAX_I2C_DEVICE_DEFERRALS) {
+ return -EPROBE_DEFER;
+ } else {
+ /* Ran out of tries. */
+ pr_notice("ran out of tries for device.\n");
+ i2c_dev->state = TIMEDOUT;
+ return -EIO;
+ }
+ }

-static int setup_tsl2563_als(enum i2c_adapter_type type)
-{
- if (als)
- return 0;
+ i2c_dev->client = client;
+ i2c_dev->state = PROBED;

- /* add tsl2563 light sensor */
- als = add_i2c_device(NULL, type, &tsl2563_als_device);
- return (!als) ? -EAGAIN : 0;
+ return 0;
}

static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
@@ -366,47 +241,22 @@ static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)

static int chromeos_laptop_probe(struct platform_device *pdev)
{
+ struct i2c_peripheral *i2c_dev;
int i;
int ret = 0;

for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
- struct i2c_peripheral *i2c_dev;
-
i2c_dev = &cros_laptop->i2c_peripherals[i];

/* No more peripherals. */
- if (i2c_dev->add == NULL)
+ if (!i2c_dev->board_info.addr)
break;

- if (i2c_dev->state == TIMEDOUT || i2c_dev->state == PROBED)
+ if (i2c_dev->state != UNPROBED)
continue;

- /*
- * Check that the i2c adapter is present.
- * -EPROBE_DEFER if missing as the adapter may appear much
- * later.
- */
- if (find_i2c_adapter_num(i2c_dev->type) == -ENODEV) {
+ if (chromeos_laptop_add_peripheral(i2c_dev) == -EPROBE_DEFER)
ret = -EPROBE_DEFER;
- continue;
- }
-
- /* Add the device. */
- if (i2c_dev->add(i2c_dev->type) == -EAGAIN) {
- /*
- * Set -EPROBE_DEFER a limited num of times
- * if device is not successfully added.
- */
- if (++i2c_dev->tries < MAX_I2C_DEVICE_DEFERRALS) {
- ret = -EPROBE_DEFER;
- } else {
- /* Ran out of tries. */
- pr_notice("ran out of tries for device.\n");
- i2c_dev->state = TIMEDOUT;
- }
- } else {
- i2c_dev->state = PROBED;
- }
}

return ret;
@@ -415,91 +265,237 @@ static int chromeos_laptop_probe(struct platform_device *pdev)
static struct chromeos_laptop samsung_series_5_550 = {
.i2c_peripherals = {
/* Touchpad. */
- { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_SMBUS,
+ },
/* Light Sensor. */
- { .add = setup_isl29018_als, I2C_ADAPTER_SMBUS },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
+ },
+ .dmi_name = "lightsensor",
+ .type = I2C_ADAPTER_SMBUS,
+ },
},
};

static struct chromeos_laptop samsung_series_5 = {
.i2c_peripherals = {
/* Light Sensor. */
- { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
+ },
+ .type = I2C_ADAPTER_SMBUS,
+ },
},
};

+static struct mxt_platform_data atmel_1664s_platform_data = {
+ .irqflags = IRQF_TRIGGER_FALLING,
+};
+
+static int chromebook_pixel_tp_keys[] = {
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ KEY_RESERVED,
+ BTN_LEFT
+};
+
+static struct mxt_platform_data chromebook_pixel_tp_platform_data = {
+ .irqflags = IRQF_TRIGGER_FALLING,
+ .t19_num_keys = ARRAY_SIZE(chromebook_pixel_tp_keys),
+ .t19_keymap = chromebook_pixel_tp_keys,
+};
+
static struct chromeos_laptop chromebook_pixel = {
.i2c_peripherals = {
/* Touch Screen. */
- { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("atmel_mxt_ts",
+ ATMEL_TS_I2C_ADDR),
+ .platform_data = &atmel_1664s_platform_data,
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "touchscreen",
+ .type = I2C_ADAPTER_PANEL,
+ .alt_addr = ATMEL_TS_I2C_BL_ADDR,
+ },
/* Touchpad. */
- { .add = setup_atmel_224s_tp, I2C_ADAPTER_VGADDC },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("atmel_mxt_tp",
+ ATMEL_TP_I2C_ADDR),
+ .platform_data =
+ &chromebook_pixel_tp_platform_data,
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_VGADDC,
+ .alt_addr = ATMEL_TP_I2C_BL_ADDR,
+ },
/* Light Sensor. */
- { .add = setup_isl29018_als, I2C_ADAPTER_PANEL },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
+ },
+ .dmi_name = "lightsensor",
+ .type = I2C_ADAPTER_PANEL,
+ },
},
};

static struct chromeos_laptop hp_chromebook_14 = {
.i2c_peripherals = {
/* Touchpad. */
- { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE_0,
+ },
},
};

static struct chromeos_laptop dell_chromebook_11 = {
.i2c_peripherals = {
/* Touchpad. */
- { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE_0,
+ },
/* Elan Touchpad option. */
- { .add = setup_elantech_tp, I2C_ADAPTER_DESIGNWARE_0 },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE_0,
+ },
},
};

static struct chromeos_laptop toshiba_cb35 = {
.i2c_peripherals = {
/* Touchpad. */
- { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE_0,
+ },
},
};

static struct chromeos_laptop acer_c7_chromebook = {
.i2c_peripherals = {
/* Touchpad. */
- { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_SMBUS,
+ },
},
};

static struct chromeos_laptop acer_ac700 = {
.i2c_peripherals = {
/* Light Sensor. */
- { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
+ },
+ .type = I2C_ADAPTER_SMBUS,
+ },
},
};

static struct chromeos_laptop acer_c720 = {
.i2c_peripherals = {
/* Touchscreen. */
- { .add = setup_atmel_1664s_ts, I2C_ADAPTER_DESIGNWARE_1 },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("atmel_mxt_ts",
+ ATMEL_TS_I2C_ADDR),
+ .platform_data = &atmel_1664s_platform_data,
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "touchscreen",
+ .type = I2C_ADAPTER_DESIGNWARE_1,
+ .alt_addr = ATMEL_TS_I2C_BL_ADDR,
+ },
/* Touchpad. */
- { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE_0,
+ },
/* Elan Touchpad option. */
- { .add = setup_elantech_tp, I2C_ADAPTER_DESIGNWARE_0 },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_DESIGNWARE_0,
+ },
/* Light Sensor. */
- { .add = setup_isl29018_als, I2C_ADAPTER_DESIGNWARE_1 },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
+ },
+ .dmi_name = "lightsensor",
+ .type = I2C_ADAPTER_DESIGNWARE_1,
+ },
},
};

static struct chromeos_laptop hp_pavilion_14_chromebook = {
.i2c_peripherals = {
/* Touchpad. */
- { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
+ .flags = I2C_CLIENT_WAKE,
+ },
+ .dmi_name = "trackpad",
+ .type = I2C_ADAPTER_SMBUS,
+ },
},
};

static struct chromeos_laptop cr48 = {
.i2c_peripherals = {
/* Light Sensor. */
- { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
+ {
+ .board_info = {
+ I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
+ },
+ .type = I2C_ADAPTER_SMBUS,
+ },
},
};

@@ -637,15 +633,22 @@ static int __init chromeos_laptop_init(void)

static void __exit chromeos_laptop_exit(void)
{
- if (als)
- i2c_unregister_device(als);
- if (tp)
- i2c_unregister_device(tp);
- if (ts)
- i2c_unregister_device(ts);
+ struct i2c_peripheral *i2c_dev;
+ int i;

platform_device_unregister(cros_platform_device);
platform_driver_unregister(&cros_platform_driver);
+
+ 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->state == PROBED)
+ i2c_unregister_device(i2c_dev->client);
+ }
}

module_init(chromeos_laptop_init);
--
2.16.2.804.g6dcf76e118-goog