Linux Input/HID development
 help / color / mirror / Atom feed
* Re: [PATCH 00/14] chrome_laptop: stop being a platform driver
From: Benson Leung @ 2018-03-12 19:17 UTC (permalink / raw)
  To: Dmitry Torokhov
  Cc: linux-input, Benson Leung, Nick Dyer, Olof Johansson,
	linux-kernel, bleung
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

[-- Attachment #1: Type: text/plain, Size: 1145 bytes --]

On Mon, Mar 12, 2018 at 12:08:53PM -0700, Dmitry Torokhov wrote:
> Hi,
> 
> This series is a combination of Atmel touchscreen driver stopping using
> platform data and moving over to generic device properties, and
> chromeos-laptop switching from being platform driver, which is the wrong
> abstraction for it, and moving to using i2c bis notifier. Switching from
> platform driver to the notifiers allows us to get rid of the ugly code that
> manually tries to handle deferrals in case i2c bus is not ready at the time
> we start initializing the module.
> 
> Benson, because chromeos-laptop is instantiating Atmel devices the 2
> changes are intertwined. While we could apply them in stages, with parts
> going through input and parts going through your tree I was wondering if we
> could speed up the process and push the series through one or another tree
> (if you are OK with the patches, of course).
> 

I'm all for this change. I can push this through my tree.

Thanks,
Benson

-- 
Benson Leung
Staff Software Engineer
Chrome OS Kernel
Google Inc.
bleung@google.com
Chromium OS Project
bleung@chromium.org

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply

* [PATCH 14/14] Input: atmel_mxt_ts - remove platform data support
From: Dmitry Torokhov @ 2018-03-12 19:09 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Now that there are no users of custom Atmel platform data, and everyone
has switched to the generic device properties, we can remove support for
the platform data.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 MAINTAINERS                                |   1 -
 drivers/input/touchscreen/atmel_mxt_ts.c   | 125 +++++++++------------
 include/linux/platform_data/atmel_mxt_ts.h |  31 -----
 3 files changed, 50 insertions(+), 107 deletions(-)
 delete mode 100644 include/linux/platform_data/atmel_mxt_ts.h

diff --git a/MAINTAINERS b/MAINTAINERS
index 4623caf8d72d8..37b70874a4771 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -2394,7 +2394,6 @@ T:	git git://github.com/ndyer/linux.git
 S:	Maintained
 F:	Documentation/devicetree/bindings/input/atmel,maxtouch.txt
 F:	drivers/input/touchscreen/atmel_mxt_ts.c
-F:	include/linux/platform_data/atmel_mxt_ts.h
 
 ATMEL SAMA5D2 ADC DRIVER
 M:	Ludovic Desroches <ludovic.desroches@microchip.com>
diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index cf2aac4e79ae8..642211254acc4 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -23,10 +23,10 @@
 #include <linux/delay.h>
 #include <linux/firmware.h>
 #include <linux/i2c.h>
-#include <linux/platform_data/atmel_mxt_ts.h>
 #include <linux/input/mt.h>
 #include <linux/interrupt.h>
 #include <linux/of.h>
+#include <linux/property.h>
 #include <linux/slab.h>
 #include <linux/gpio/consumer.h>
 #include <linux/property.h>
@@ -274,7 +274,6 @@ struct mxt_data {
 	struct i2c_client *client;
 	struct input_dev *input_dev;
 	char phys[64];		/* device physical location */
-	const struct mxt_platform_data *pdata;
 	struct mxt_object *object_table;
 	struct mxt_info info;
 	unsigned int irq;
@@ -325,6 +324,9 @@ struct mxt_data {
 
 	/* for config update handling */
 	struct completion crc_completion;
+
+	u32 *t19_keymap;
+	unsigned int t19_num_keys;
 };
 
 struct mxt_vb2_buffer {
@@ -743,15 +745,14 @@ static int mxt_write_object(struct mxt_data *data,
 static void mxt_input_button(struct mxt_data *data, u8 *message)
 {
 	struct input_dev *input = data->input_dev;
-	const struct mxt_platform_data *pdata = data->pdata;
 	int i;
 
-	for (i = 0; i < pdata->t19_num_keys; i++) {
-		if (pdata->t19_keymap[i] == KEY_RESERVED)
+	for (i = 0; i < data->t19_num_keys; i++) {
+		if (data->t19_keymap[i] == KEY_RESERVED)
 			continue;
 
 		/* Active-low switch */
-		input_report_key(input, pdata->t19_keymap[i],
+		input_report_key(input, data->t19_keymap[i],
 				 !(message[1] & BIT(i)));
 	}
 }
@@ -759,7 +760,7 @@ static void mxt_input_button(struct mxt_data *data, u8 *message)
 static void mxt_input_sync(struct mxt_data *data)
 {
 	input_mt_report_pointer_emulation(data->input_dev,
-					  data->pdata->t19_num_keys);
+					  data->t19_num_keys);
 	input_sync(data->input_dev);
 }
 
@@ -1859,7 +1860,6 @@ static void mxt_input_close(struct input_dev *dev);
 static void mxt_set_up_as_touchpad(struct input_dev *input_dev,
 				   struct mxt_data *data)
 {
-	const struct mxt_platform_data *pdata = data->pdata;
 	int i;
 
 	input_dev->name = "Atmel maXTouch Touchpad";
@@ -1873,15 +1873,14 @@ static void mxt_set_up_as_touchpad(struct input_dev *input_dev,
 	input_abs_set_res(input_dev, ABS_MT_POSITION_Y,
 			  MXT_PIXELS_PER_MM);
 
-	for (i = 0; i < pdata->t19_num_keys; i++)
-		if (pdata->t19_keymap[i] != KEY_RESERVED)
+	for (i = 0; i < data->t19_num_keys; i++)
+		if (data->t19_keymap[i] != KEY_RESERVED)
 			input_set_capability(input_dev, EV_KEY,
-					     pdata->t19_keymap[i]);
+					     data->t19_keymap[i]);
 }
 
 static int mxt_initialize_input_device(struct mxt_data *data)
 {
-	const struct mxt_platform_data *pdata = data->pdata;
 	struct device *dev = &data->client->dev;
 	struct input_dev *input_dev;
 	int error;
@@ -1947,7 +1946,7 @@ static int mxt_initialize_input_device(struct mxt_data *data)
 	}
 
 	/* If device has buttons we assume it is a touchpad */
-	if (pdata->t19_num_keys) {
+	if (data->t19_num_keys) {
 		mxt_set_up_as_touchpad(input_dev, data);
 		mt_flags |= INPUT_MT_POINTER;
 	} else {
@@ -2921,51 +2920,42 @@ static void mxt_input_close(struct input_dev *dev)
 	mxt_stop(data);
 }
 
-static const struct mxt_platform_data *
-mxt_parse_device_properties(struct i2c_client *client)
+static int mxt_parse_device_properties(struct mxt_data *data)
 {
 	static const char keymap_property[] = "linux,gpio-keymap";
-	struct mxt_platform_data *pdata;
+	struct device *dev = &data->client->dev;
 	u32 *keymap;
 	int n_keys;
 	int error;
 
-	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
-	if (!pdata)
-		return ERR_PTR(-ENOMEM);
-
-	if (device_property_present(&client->dev, keymap_property)) {
-		n_keys = device_property_read_u32_array(&client->dev,
-							keymap_property,
+	if (device_property_present(dev, keymap_property)) {
+		n_keys = device_property_read_u32_array(dev, keymap_property,
 							NULL, 0);
 		if (n_keys <= 0) {
 			error = n_keys < 0 ? n_keys : -EINVAL;
-			dev_err(&client->dev,
-				"invalid/malformed '%s' property: %d\n",
+			dev_err(dev, "invalid/malformed '%s' property: %d\n",
 				keymap_property, error);
-			return ERR_PTR(error);
+			return error;
 		}
 
-		keymap = devm_kmalloc_array(&client->dev, n_keys, sizeof(u32),
+		keymap = devm_kmalloc_array(dev, n_keys, sizeof(*keymap),
 					    GFP_KERNEL);
 		if (!keymap)
-			return ERR_PTR(-ENOMEM);
+			return -ENOMEM;
 
-		error = device_property_read_u32_array(&client->dev,
-						       keymap_property,
+		error = device_property_read_u32_array(dev, keymap_property,
 						       keymap, n_keys);
 		if (error) {
-			dev_err(&client->dev,
-				"failed to parse '%s' property: %d\n",
+			dev_err(dev, "failed to parse '%s' property: %d\n",
 				keymap_property, error);
-			return ERR_PTR(error);
+			return error;
 		}
 
-		pdata->t19_keymap = keymap;
-		pdata->t19_num_keys = n_keys;
+		data->t19_keymap = keymap;
+		data->t19_num_keys = n_keys;
 	}
 
-	return pdata;
+	return 0;
 }
 
 #ifdef CONFIG_ACPI
@@ -3048,25 +3038,12 @@ static const struct dmi_system_id mxt_dmi_table[] = {
 	{ }
 };
 
-static int mxt_acpi_probe(struct i2c_client *client)
+static int mxt_prepare_acpi_properties(struct i2c_client *client)
 {
 	struct acpi_device *adev;
 	const struct dmi_system_id *system_id;
 	const struct mxt_acpi_platform_data *acpi_pdata;
 
-	/*
-	 * Ignore ACPI devices representing bootloader mode.
-	 *
-	 * This is a bit of a hack: Google Chromebook BIOS creates ACPI
-	 * devices for both application and bootloader modes, but we are
-	 * interested in application mode only (if device is in bootloader
-	 * mode we'll end up switching into application anyway). So far
-	 * application mode addresses were all above 0x40, so we'll use it
-	 * as a threshold.
-	 */
-	if (client->addr < 0x40)
-		return -ENXIO;
-
 	adev = ACPI_COMPANION(&client->dev);
 	if (!adev)
 		return -ENOENT;
@@ -3102,37 +3079,29 @@ static int mxt_acpi_probe(struct i2c_client *client)
 	return 0;
 }
 #else
-static int mxt_acpi_probe(struct i2c_client *client)
+static int mxt_prepare_acpi_properties(struct i2c_client *client)
 {
 	return -ENOENT;
 }
 #endif
 
-static const struct mxt_platform_data *
-mxt_get_platform_data(struct i2c_client *client)
-{
-	const struct mxt_platform_data *pdata;
-
-	pdata = dev_get_platdata(&client->dev);
-	if (pdata)
-		return pdata;
-
-	return mxt_parse_device_properties(client);
-}
-
 static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
 {
 	struct mxt_data *data;
-	const struct mxt_platform_data *pdata;
 	int error;
 
-	error = mxt_acpi_probe(client);
-	if (error && error != -ENOENT)
-		return error;
-
-	pdata = mxt_get_platform_data(client);
-	if (IS_ERR(pdata))
-		return PTR_ERR(pdata);
+	/*
+	 * Ignore ACPI devices representing bootloader mode.
+	 *
+	 * This is a bit of a hack: Google Chromebook BIOS creates ACPI
+	 * devices for both application and bootloader modes, but we are
+	 * interested in application mode only (if device is in bootloader
+	 * mode we'll end up switching into application anyway). So far
+	 * application mode addresses were all above 0x40, so we'll use it
+	 * as a threshold.
+	 */
+	if (ACPI_COMPANION(&client->dev) && client->addr < 0x40)
+		return -ENXIO;
 
 	data = devm_kzalloc(&client->dev, sizeof(struct mxt_data), GFP_KERNEL);
 	if (!data)
@@ -3142,7 +3111,6 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
 		 client->adapter->nr, client->addr);
 
 	data->client = client;
-	data->pdata = pdata;
 	data->irq = client->irq;
 	i2c_set_clientdata(client, data);
 
@@ -3150,6 +3118,14 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	init_completion(&data->reset_completion);
 	init_completion(&data->crc_completion);
 
+	error = mxt_prepare_acpi_properties(client);
+	if (error && error != -ENOENT)
+		return error;
+
+	error = mxt_parse_device_properties(data);
+	if (error)
+		return error;
+
 	data->reset_gpio = devm_gpiod_get_optional(&client->dev,
 						   "reset", GPIOD_OUT_LOW);
 	if (IS_ERR(data->reset_gpio)) {
@@ -3159,8 +3135,7 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	}
 
 	error = devm_request_threaded_irq(&client->dev, client->irq,
-					  NULL, mxt_interrupt,
-					  pdata->irqflags | IRQF_ONESHOT,
+					  NULL, mxt_interrupt, IRQF_ONESHOT,
 					  client->name, data);
 	if (error) {
 		dev_err(&client->dev, "Failed to register interrupt\n");
@@ -3280,7 +3255,7 @@ MODULE_DEVICE_TABLE(i2c, mxt_id);
 static struct i2c_driver mxt_driver = {
 	.driver = {
 		.name	= "atmel_mxt_ts",
-		.of_match_table = of_match_ptr(mxt_of_match),
+		.of_match_table = mxt_of_match,
 		.acpi_match_table = ACPI_PTR(mxt_acpi_id),
 		.pm	= &mxt_pm_ops,
 	},
diff --git a/include/linux/platform_data/atmel_mxt_ts.h b/include/linux/platform_data/atmel_mxt_ts.h
deleted file mode 100644
index 695035a8d7fb9..0000000000000
--- a/include/linux/platform_data/atmel_mxt_ts.h
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Atmel maXTouch Touchscreen driver
- *
- * Copyright (C) 2010 Samsung Electronics Co.Ltd
- * Author: Joonyoung Shim <jy0922.shim@samsung.com>
- *
- * 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.
- */
-
-#ifndef __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H
-#define __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H
-
-#include <linux/types.h>
-
-enum mxt_suspend_mode {
-	MXT_SUSPEND_DEEP_SLEEP	= 0,
-	MXT_SUSPEND_T9_CTRL	= 1,
-};
-
-/* The platform data for the Atmel maXTouch touchscreen driver */
-struct mxt_platform_data {
-	unsigned long irqflags;
-	u8 t19_num_keys;
-	const unsigned int *t19_keymap;
-	enum mxt_suspend_mode suspend_mode;
-};
-
-#endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 13/14] platform/chrome: chromeos_laptop - discard data for unneeded boards
From: Dmitry Torokhov @ 2018-03-12 19:09 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Mark board data as __intconst/__initdata and make a copy of appropriate
entry once we identified the board we are running on. The rest of the data
will be discarded once the kernel finished booting (or module finished
loading).

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 476 ++++++++++++----------
 1 file changed, 264 insertions(+), 212 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index fe83a2a4900e4..5c47f451e43b1 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);
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 12/14] platform/chrome: chromeos_laptop - use device properties for Pixel
From: Dmitry Torokhov @ 2018-03-12 19:09 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Now that Atmel driver uses generic device properties we can use them
instead of platform data when setting up touchpad on the original
Google Pixel.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 12 ++++++------
 1 file changed, 6 insertions(+), 6 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 1191c1a3a0cd1..fe83a2a4900e4 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -8,13 +8,13 @@
 
 #include <linux/dmi.h>
 #include <linux/i2c.h>
-#include <linux/platform_data/atmel_mxt_ts.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
+#include <linux/property.h>
 
 #define ATMEL_TP_I2C_ADDR	0x4b
 #define ATMEL_TP_I2C_BL_ADDR	0x25
@@ -229,9 +229,9 @@ static int chromebook_pixel_tp_keys[] = {
 	BTN_LEFT
 };
 
-static struct mxt_platform_data chromebook_pixel_tp_platform_data = {
-	.t19_num_keys		= ARRAY_SIZE(chromebook_pixel_tp_keys),
-	.t19_keymap		= chromebook_pixel_tp_keys,
+static const struct property_entry chromebook_pixel_trackpad_props[] = {
+	PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
+	{ }
 };
 
 static struct chromeos_laptop chromebook_pixel = {
@@ -253,8 +253,8 @@ static struct chromeos_laptop chromebook_pixel = {
 			.board_info	= {
 				I2C_BOARD_INFO("atmel_mxt_tp",
 						ATMEL_TP_I2C_ADDR),
-				.platform_data	=
-					&chromebook_pixel_tp_platform_data,
+				.properties	=
+					chromebook_pixel_trackpad_props,
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "trackpad",
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 11/14] platform/chrome: chromeos_laptop - rely on I2C to set up interrupt trigger
From: Dmitry Torokhov @ 2018-03-12 19:09 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Instead of passing interrupt flags via platform data to drivers, or
hoping that drivers will do the right thing and set it up the way we
need, let's set up IRQ resource and attach it to the I2C board info, and
let I2C core set it up for us.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 21 ++++++++++++++-------
 1 file changed, 14 insertions(+), 7 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index e5015dfaa81ec..1191c1a3a0cd1 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -11,6 +11,7 @@
 #include <linux/platform_data/atmel_mxt_ts.h>
 #include <linux/input.h>
 #include <linux/interrupt.h>
+#include <linux/ioport.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/platform_device.h>
@@ -42,7 +43,11 @@ enum i2c_adapter_type {
 struct i2c_peripheral {
 	struct i2c_board_info board_info;
 	unsigned short alt_addr;
+
 	const char *dmi_name;
+	unsigned long irqflags;
+	struct resource irq_resource;
+
 	enum i2c_adapter_type type;
 	u32 pci_devid;
 
@@ -215,10 +220,6 @@ static struct chromeos_laptop samsung_series_5 = {
 	},
 };
 
-static struct mxt_platform_data atmel_1664s_platform_data = {
-	.irqflags		= IRQF_TRIGGER_FALLING,
-};
-
 static int chromebook_pixel_tp_keys[] = {
 	KEY_RESERVED,
 	KEY_RESERVED,
@@ -229,7 +230,6 @@ static int chromebook_pixel_tp_keys[] = {
 };
 
 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,
 };
@@ -241,10 +241,10 @@ static struct chromeos_laptop chromebook_pixel = {
 			.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",
+			.irqflags	= IRQF_TRIGGER_FALLING,
 			.type		= I2C_ADAPTER_PANEL,
 			.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
 		},
@@ -258,6 +258,7 @@ static struct chromeos_laptop chromebook_pixel = {
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "trackpad",
+			.irqflags	= IRQF_TRIGGER_FALLING,
 			.type		= I2C_ADAPTER_VGADDC,
 			.alt_addr	= ATMEL_TP_I2C_BL_ADDR,
 		},
@@ -356,10 +357,10 @@ static struct chromeos_laptop acer_c720 = {
 			.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",
+			.irqflags	= IRQF_TRIGGER_FALLING,
 			.type		= I2C_ADAPTER_DESIGNWARE,
 			.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
 			.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
@@ -558,6 +559,12 @@ chromeos_laptop_prepare(const struct dmi_system_id *id)
 		irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
 		if (irq < 0)
 			return ERR_PTR(irq);
+
+		i2c_dev->irq_resource  = (struct resource)
+			DEFINE_RES_NAMED(irq, 1, NULL,
+					 IORESOURCE_IRQ | i2c_dev->irqflags);
+		i2c_dev->board_info.resources = &i2c_dev->irq_resource;
+		i2c_dev->board_info.num_resources = 1;
 	}
 
 	return cros_laptop;
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 10/14] platform/chrome: chromeos_laptop - use I2C notifier to create devices
From: Dmitry Torokhov @ 2018-03-12 19:09 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Instead of using platform device and deferrals to handle the case when i2C
adapters appear late in the game, and not handling device unbinding all
that well, let's switch to using I2C bus notifier to get told when a new
I2C adapter appears in the system, and attempt to add appropriate devices
at that time.

In case when we have 2 Designware adapters in the system (Acer C720),
instead of counting and hoping they get enumerate din the right order,
let's switch to using their PCI devids (slot/function) that should be
stable.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 247 +++++++++-------------
 1 file changed, 102 insertions(+), 145 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index d6d2bc6f3aaf0..e5015dfaa81ec 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -12,6 +12,7 @@
 #include <linux/input.h>
 #include <linux/interrupt.h>
 #include <linux/module.h>
+#include <linux/pci.h>
 #include <linux/platform_device.h>
 
 #define ATMEL_TP_I2C_ADDR	0x4b
@@ -23,14 +24,11 @@
 #define ISL_ALS_I2C_ADDR	0x44
 #define TAOS_ALS_I2C_ADDR	0x29
 
-#define MAX_I2C_DEVICE_DEFERRALS	5
-
 static const char *i2c_adapter_names[] = {
 	"SMBus I801 adapter",
 	"i915 gmbus vga",
 	"i915 gmbus panel",
 	"Synopsys DesignWare I2C adapter",
-	"Synopsys DesignWare I2C adapter",
 };
 
 /* Keep this enum consistent with i2c_adapter_names */
@@ -38,15 +36,7 @@ enum i2c_adapter_type {
 	I2C_ADAPTER_SMBUS = 0,
 	I2C_ADAPTER_VGADDC,
 	I2C_ADAPTER_PANEL,
-	I2C_ADAPTER_DESIGNWARE_0,
-	I2C_ADAPTER_DESIGNWARE_1,
-};
-
-enum i2c_peripheral_state {
-	UNPROBED = 0,
-	PROBED,
-	TIMEDOUT,
-	FAILED,
+	I2C_ADAPTER_DESIGNWARE,
 };
 
 struct i2c_peripheral {
@@ -54,10 +44,9 @@ struct i2c_peripheral {
 	unsigned short alt_addr;
 	const char *dmi_name;
 	enum i2c_adapter_type type;
+	u32 pci_devid;
 
-	enum i2c_peripheral_state state;
 	struct i2c_client *client;
-	int tries;
 };
 
 #define MAX_I2C_PERIPHERALS 4
@@ -69,19 +58,12 @@ struct chromeos_laptop {
 static struct chromeos_laptop *cros_laptop;
 
 static struct i2c_client *
-chromes_laptop_instantiate_i2c_device(int bus,
+chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter,
 				      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 };
-
-	adapter = i2c_get_adapter(bus);
-	if (!adapter) {
-		pr_err("failed to get i2c adapter %d\n", bus);
-		return NULL;
-	}
+	struct i2c_client *client;
 
 	/*
 	 * Add the i2c device. If we can't detect it at the primary
@@ -102,126 +84,103 @@ chromes_laptop_instantiate_i2c_device(int bus,
 					      alt_addr_list, NULL);
 		if (dummy) {
 			pr_debug("%d-%02x is probed at %02x\n",
-				 bus, info->addr, dummy->addr);
+				 adapter->nr, info->addr, dummy->addr);
 			i2c_unregister_device(dummy);
 			client = i2c_new_device(adapter, info);
 		}
 	}
 
 	if (!client)
-		pr_notice("failed to register device %d-%02x\n",
-			  bus, info->addr);
+		pr_debug("failed to register device %d-%02x\n",
+			 adapter->nr, info->addr);
 	else
-		pr_debug("added i2c device %d-%02x\n", bus, info->addr);
+		pr_debug("added i2c device %d-%02x\n",
+			 adapter->nr, info->addr);
 
-	i2c_put_adapter(adapter);
 	return client;
 }
 
-struct i2c_lookup {
-	const char *name;
-	int instance;
-	int n;
-};
-
-static int __find_i2c_adap(struct device *dev, void *data)
+static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid)
 {
-	struct i2c_lookup *lookup = data;
-	static const char *prefix = "i2c-";
-	struct i2c_adapter *adapter;
+	struct pci_dev *pdev;
 
-	if (strncmp(dev_name(dev), prefix, strlen(prefix)) != 0)
-		return 0;
-	adapter = to_i2c_adapter(dev);
-	if (strncmp(adapter->name, lookup->name, strlen(lookup->name)) == 0 &&
-	    lookup->n++ == lookup->instance)
-		return 1;
-	return 0;
-}
+	if (!dev_is_pci(dev))
+		return false;
 
-static int find_i2c_adapter_num(enum i2c_adapter_type type)
-{
-	struct device *dev = NULL;
-	struct i2c_adapter *adapter;
-	struct i2c_lookup lookup;
-
-	memset(&lookup, 0, sizeof(lookup));
-	lookup.name = i2c_adapter_names[type];
-	lookup.instance = (type == I2C_ADAPTER_DESIGNWARE_1) ? 1 : 0;
-
-	/* find the adapter by name */
-	dev = bus_find_device(&i2c_bus_type, NULL, &lookup, __find_i2c_adap);
-	if (!dev) {
-		/* Adapters may appear later. Deferred probing will retry */
-		pr_notice("i2c adapter %s not found on system.\n",
-			  lookup.name);
-		return -ENODEV;
-	}
-	adapter = to_i2c_adapter(dev);
-	return adapter->nr;
+	pdev = to_pci_dev(dev);
+	return devid == PCI_DEVID(pdev->bus->number, pdev->devfn);
 }
 
-static int chromeos_laptop_add_peripheral(struct i2c_peripheral *i2c_dev)
+static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
 {
-	struct i2c_client *client;
-	int bus;
+	struct i2c_peripheral *i2c_dev;
+	int i;
 
-	/*
-	 * 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;
-
-	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;
-		}
-	}
+	for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
+		i2c_dev = &cros_laptop->i2c_peripherals[i];
 
-	i2c_dev->client = client;
-	i2c_dev->state = PROBED;
+		/* No more peripherals */
+		if (!i2c_dev->board_info.addr)
+			break;
 
-	return 0;
+		/* Skip devices already created */
+		if (i2c_dev->client)
+			continue;
+
+		if (strncmp(adapter->name, i2c_adapter_names[i2c_dev->type],
+			    strlen(i2c_adapter_names[i2c_dev->type])))
+			continue;
+
+		if (i2c_dev->pci_devid &&
+		    !chromeos_laptop_match_adapter_devid(adapter->dev.parent,
+							 i2c_dev->pci_devid)) {
+			continue;
+		}
+
+		i2c_dev->client =
+			chromes_laptop_instantiate_i2c_device(adapter,
+							&i2c_dev->board_info,
+							i2c_dev->alt_addr);
+	}
 }
 
-static int chromeos_laptop_probe(struct platform_device *pdev)
+static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
 {
 	struct i2c_peripheral *i2c_dev;
 	int i;
-	int ret = 0;
 
 	for (i = 0; i < MAX_I2C_PERIPHERALS; i++) {
 		i2c_dev = &cros_laptop->i2c_peripherals[i];
 
-		/* No more peripherals. */
-		if (!i2c_dev->board_info.addr)
-			break;
-
-		if (i2c_dev->state != UNPROBED)
-			continue;
+		if (i2c_dev->client == client)
+			i2c_dev->client = NULL;
+	}
+}
 
-		if (chromeos_laptop_add_peripheral(i2c_dev) == -EPROBE_DEFER)
-			ret = -EPROBE_DEFER;
+static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
+					     unsigned long action, void *data)
+{
+	struct device *dev = data;
+
+	switch (action) {
+	case BUS_NOTIFY_ADD_DEVICE:
+		if (dev->type == &i2c_adapter_type)
+			chromeos_laptop_check_adapter(to_i2c_adapter(dev));
+		break;
+
+	case BUS_NOTIFY_REMOVED_DEVICE:
+		if (dev->type == &i2c_client_type)
+			chromeos_laptop_detach_i2c_client(to_i2c_client(dev));
+		break;
 	}
 
-	return ret;
+	return 0;
 }
 
+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. */
@@ -322,7 +281,7 @@ static struct chromeos_laptop hp_chromebook_14 = {
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "trackpad",
-			.type		= I2C_ADAPTER_DESIGNWARE_0,
+			.type		= I2C_ADAPTER_DESIGNWARE,
 		},
 	},
 };
@@ -336,7 +295,7 @@ static struct chromeos_laptop dell_chromebook_11 = {
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "trackpad",
-			.type		= I2C_ADAPTER_DESIGNWARE_0,
+			.type		= I2C_ADAPTER_DESIGNWARE,
 		},
 		/* Elan Touchpad option. */
 		{
@@ -345,7 +304,7 @@ static struct chromeos_laptop dell_chromebook_11 = {
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "trackpad",
-			.type		= I2C_ADAPTER_DESIGNWARE_0,
+			.type		= I2C_ADAPTER_DESIGNWARE,
 		},
 	},
 };
@@ -359,7 +318,7 @@ static struct chromeos_laptop toshiba_cb35 = {
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "trackpad",
-			.type		= I2C_ADAPTER_DESIGNWARE_0,
+			.type		= I2C_ADAPTER_DESIGNWARE,
 		},
 	},
 };
@@ -401,7 +360,8 @@ static struct chromeos_laptop acer_c720 = {
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "touchscreen",
-			.type		= I2C_ADAPTER_DESIGNWARE_1,
+			.type		= I2C_ADAPTER_DESIGNWARE,
+			.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
 			.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
 		},
 		/* Touchpad. */
@@ -411,7 +371,8 @@ static struct chromeos_laptop acer_c720 = {
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "trackpad",
-			.type		= I2C_ADAPTER_DESIGNWARE_0,
+			.type		= I2C_ADAPTER_DESIGNWARE,
+			.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
 		},
 		/* Elan Touchpad option. */
 		{
@@ -420,7 +381,8 @@ static struct chromeos_laptop acer_c720 = {
 				.flags		= I2C_CLIENT_WAKE,
 			},
 			.dmi_name	= "trackpad",
-			.type		= I2C_ADAPTER_DESIGNWARE_0,
+			.type		= I2C_ADAPTER_DESIGNWARE,
+			.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
 		},
 		/* Light Sensor. */
 		{
@@ -428,7 +390,8 @@ static struct chromeos_laptop acer_c720 = {
 				I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
 			},
 			.dmi_name	= "lightsensor",
-			.type		= I2C_ADAPTER_DESIGNWARE_1,
+			.type		= I2C_ADAPTER_DESIGNWARE,
+			.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
 		},
 	},
 };
@@ -546,14 +509,16 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
 };
 MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
 
-static struct platform_device *cros_platform_device;
+static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data)
+{
+	struct i2c_adapter *adapter;
 
-static struct platform_driver cros_platform_driver = {
-	.driver = {
-		.name = "chromeos_laptop",
-	},
-	.probe = chromeos_laptop_probe,
-};
+	adapter = i2c_verify_adapter(dev);
+	if (adapter)
+		chromeos_laptop_check_adapter(adapter);
+
+	return 0;
+}
 
 static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
 {
@@ -602,7 +567,7 @@ chromeos_laptop_prepare(const struct dmi_system_id *id)
 static int __init chromeos_laptop_init(void)
 {
 	const struct dmi_system_id *dmi_id;
-	int ret;
+	int error;
 
 	dmi_id = dmi_first_match(chromeos_laptop_dmi_table);
 	if (!dmi_id) {
@@ -616,27 +581,20 @@ static int __init chromeos_laptop_init(void)
 	if (IS_ERR(cros_laptop))
 		return PTR_ERR(cros_laptop);
 
-	ret = platform_driver_register(&cros_platform_driver);
-	if (ret)
-		return ret;
-
-	cros_platform_device = platform_device_alloc("chromeos_laptop", -1);
-	if (!cros_platform_device) {
-		ret = -ENOMEM;
-		goto fail_platform_device1;
+	error = bus_register_notifier(&i2c_bus_type,
+				      &chromeos_laptop_i2c_notifier);
+	if (error) {
+		pr_err("failed to register i2c bus notifier: %d\n", error);
+		return error;
 	}
 
-	ret = platform_device_add(cros_platform_device);
-	if (ret)
-		goto fail_platform_device2;
+	/*
+	 * Scan adapters that have been registered before we installed
+	 * the notifier to make sure we do not miss any devices.
+	 */
+	i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter);
 
 	return 0;
-
-fail_platform_device2:
-	platform_device_put(cros_platform_device);
-fail_platform_device1:
-	platform_driver_unregister(&cros_platform_driver);
-	return ret;
 }
 
 static void __exit chromeos_laptop_exit(void)
@@ -644,8 +602,7 @@ static void __exit chromeos_laptop_exit(void)
 	struct i2c_peripheral *i2c_dev;
 	int i;
 
-	platform_device_unregister(cros_platform_device);
-	platform_driver_unregister(&cros_platform_driver);
+	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];
@@ -654,7 +611,7 @@ static void __exit chromeos_laptop_exit(void)
 		if (!i2c_dev->board_info.type)
 			break;
 
-		if (i2c_dev->state == PROBED)
+		if (i2c_dev->client)
 			i2c_unregister_device(i2c_dev->client);
 	}
 }
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 09/14] platform/chrome: chromeos_laptop - parse DMI IRQ data once
From: Dmitry Torokhov @ 2018-03-12 19:09 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Instead of trying to parse DMI IRQ data every time we try to instantiate a
device, let's do it once, when we identify the device we are working with.
This allows us to mark chromeos_laptop_get_irq_from_dmi() as __init and
discard it once module is initialized.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 120 ++++++++++++----------
 1 file changed, 64 insertions(+), 56 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 2a81ae4c15c93..d6d2bc6f3aaf0 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -68,26 +68,6 @@ struct chromeos_laptop {
 
 static struct chromeos_laptop *cros_laptop;
 
-static int chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
-{
-	const struct dmi_device *dmi_dev;
-	const struct dmi_dev_onboard *dev_data;
-
-	dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL);
-	if (!dmi_dev) {
-		pr_err("failed to find DMI device '%s'\n", dmi_name);
-		return -ENOENT;
-	}
-
-	dev_data = dmi_dev->device_data;
-	if (!dev_data) {
-		pr_err("failed to get data from DMI for '%s'\n", dmi_name);
-		return -EINVAL;
-	}
-
-	return dev_data->instance;
-}
-
 static struct i2c_client *
 chromes_laptop_instantiate_i2c_device(int bus,
 				      struct i2c_board_info *info,
@@ -185,7 +165,6 @@ static int chromeos_laptop_add_peripheral(struct i2c_peripheral *i2c_dev)
 {
 	struct i2c_client *client;
 	int bus;
-	int irq;
 
 	/*
 	 * Check that the i2c adapter is present.
@@ -196,16 +175,6 @@ static int chromeos_laptop_add_peripheral(struct i2c_peripheral *i2c_dev)
 	if (bus < 0)
 		return bus == -ENODEV ? -EPROBE_DEFER : bus;
 
-	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;
-		}
-
-		i2c_dev->board_info.irq = irq;
-	}
-
 	client = chromes_laptop_instantiate_i2c_device(bus,
 						       &i2c_dev->board_info,
 						       i2c_dev->alt_addr);
@@ -230,15 +199,6 @@ static int chromeos_laptop_add_peripheral(struct i2c_peripheral *i2c_dev)
 	return 0;
 }
 
-static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
-{
-	cros_laptop = (void *)id->driver_data;
-	pr_debug("DMI Matched %s\n", id->ident);
-
-	/* Indicate to dmi_scan that processing is done. */
-	return 1;
-}
-
 static int chromeos_laptop_probe(struct platform_device *pdev)
 {
 	struct i2c_peripheral *i2c_dev;
@@ -499,10 +459,6 @@ static struct chromeos_laptop cr48 = {
 	},
 };
 
-#define _CBDD(board_) \
-	.callback = chromeos_laptop_dmi_matched, \
-	.driver_data = (void *)&board_
-
 static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
 	{
 		.ident = "Samsung Series 5 550",
@@ -510,14 +466,14 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
 		},
-		_CBDD(samsung_series_5_550),
+		.driver_data = (void *)&samsung_series_5_550,
 	},
 	{
 		.ident = "Samsung Series 5",
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
 		},
-		_CBDD(samsung_series_5),
+		.driver_data = (void *)&samsung_series_5,
 	},
 	{
 		.ident = "Chromebook Pixel",
@@ -525,7 +481,7 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
 		},
-		_CBDD(chromebook_pixel),
+		.driver_data = (void *)&chromebook_pixel,
 	},
 	{
 		.ident = "Wolf",
@@ -533,7 +489,7 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"),
 		},
-		_CBDD(dell_chromebook_11),
+		.driver_data = (void *)&dell_chromebook_11,
 	},
 	{
 		.ident = "HP Chromebook 14",
@@ -541,7 +497,7 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Falco"),
 		},
-		_CBDD(hp_chromebook_14),
+		.driver_data = (void *)&hp_chromebook_14,
 	},
 	{
 		.ident = "Toshiba CB35",
@@ -549,42 +505,42 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
 			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
 			DMI_MATCH(DMI_PRODUCT_NAME, "Leon"),
 		},
-		_CBDD(toshiba_cb35),
+		.driver_data = (void *)&toshiba_cb35,
 	},
 	{
 		.ident = "Acer C7 Chromebook",
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
 		},
-		_CBDD(acer_c7_chromebook),
+		.driver_data = (void *)&acer_c7_chromebook,
 	},
 	{
 		.ident = "Acer AC700",
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
 		},
-		_CBDD(acer_ac700),
+		.driver_data = (void *)&acer_ac700,
 	},
 	{
 		.ident = "Acer C720",
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
 		},
-		_CBDD(acer_c720),
+		.driver_data = (void *)&acer_c720,
 	},
 	{
 		.ident = "HP Pavilion 14 Chromebook",
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
 		},
-		_CBDD(hp_pavilion_14_chromebook),
+		.driver_data = (void *)&hp_pavilion_14_chromebook,
 	},
 	{
 		.ident = "Cr-48",
 		.matches = {
 			DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
 		},
-		_CBDD(cr48),
+		.driver_data = (void *)&cr48,
 	},
 	{ }
 };
@@ -599,15 +555,67 @@ static struct platform_driver cros_platform_driver = {
 	.probe = chromeos_laptop_probe,
 };
 
+static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
+{
+	const struct dmi_device *dmi_dev;
+	const struct dmi_dev_onboard *dev_data;
+
+	dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL);
+	if (!dmi_dev) {
+		pr_err("failed to find DMI device '%s'\n", dmi_name);
+		return -ENOENT;
+	}
+
+	dev_data = dmi_dev->device_data;
+	if (!dev_data) {
+		pr_err("failed to get data from DMI for '%s'\n", dmi_name);
+		return -EINVAL;
+	}
+
+	return dev_data->instance;
+}
+
+static struct chromeos_laptop * __init
+chromeos_laptop_prepare(const struct dmi_system_id *id)
+{
+	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;
+
+		irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
+		if (irq < 0)
+			return ERR_PTR(irq);
+	}
+
+	return cros_laptop;
+}
+
+
 static int __init chromeos_laptop_init(void)
 {
+	const struct dmi_system_id *dmi_id;
 	int ret;
 
-	if (!dmi_check_system(chromeos_laptop_dmi_table)) {
+	dmi_id = dmi_first_match(chromeos_laptop_dmi_table);
+	if (!dmi_id) {
 		pr_debug("unsupported system\n");
 		return -ENODEV;
 	}
 
+	pr_debug("DMI Matched %s\n", dmi_id->ident);
+
+	cros_laptop = chromeos_laptop_prepare(dmi_id->driver_data);
+	if (IS_ERR(cros_laptop))
+		return PTR_ERR(cros_laptop);
+
 	ret = platform_driver_register(&cros_platform_driver);
 	if (ret)
 		return ret;
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 08/14] platform/chrome: chromeos_laptop - rework i2c peripherals initialization
From: Dmitry Torokhov @ 2018-03-12 19:09 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

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@gmail.com>
---
 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.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 07/14] platform/chrome: chromeos_laptop - factor out getting IRQ from DMI
From: Dmitry Torokhov @ 2018-03-12 19:09 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

This will make code instantiating I2C device a bit clearer.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 35 +++++++++++++++--------
 1 file changed, 23 insertions(+), 12 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 08ce7a105e768..96e962ff38e87 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -120,36 +120,47 @@ static struct i2c_board_info atmel_1664s_device = {
 	.flags		= I2C_CLIENT_WAKE,
 };
 
+static int chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
+{
+	const struct dmi_device *dmi_dev;
+	const struct dmi_dev_onboard *dev_data;
+
+	dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL);
+	if (!dmi_dev) {
+		pr_err("failed to find DMI device '%s'\n", dmi_name);
+		return -ENOENT;
+	}
+
+	dev_data = dmi_dev->device_data;
+	if (!dev_data) {
+		pr_err("failed to get data from DMI for '%s'\n", dmi_name);
+		return -EINVAL;
+	}
+
+	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)
 {
-	const struct dmi_device *dmi_dev;
-	const struct dmi_dev_onboard *dev_data;
 	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) {
-		dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, name, NULL);
-		if (!dmi_dev) {
-			pr_err("failed to dmi find device %s\n", name);
-			return NULL;
-		}
-		dev_data = (struct dmi_dev_onboard *)dmi_dev->device_data;
-		if (!dev_data) {
-			pr_err("failed to get data from dmi for %s\n", name);
+		info->irq = chromeos_laptop_get_irq_from_dmi(name);
+		if (info->irq < 0)
 			return NULL;
-		}
-		info->irq = dev_data->instance;
 	}
 
 	adapter = i2c_get_adapter(bus);
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 06/14] platform/chrome: chromeos_laptop - introduce pr_fmt()
From: Dmitry Torokhov @ 2018-03-12 19:08 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Define pr_fmt() to standardize driver messages.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 31 ++++++++++-------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 0a43f1833de3f..08ce7a105e768 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -4,6 +4,8 @@
 // Copyright (C) 2012 Google, Inc.
 // Author: Benson Leung <bleung@chromium.org>
 
+#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
+
 #include <linux/dmi.h>
 #include <linux/i2c.h>
 #include <linux/platform_data/atmel_mxt_ts.h>
@@ -139,15 +141,12 @@ static struct i2c_client *__add_probed_i2c_device(
 	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);
+			pr_err("failed to dmi find device %s\n", 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);
+			pr_err("failed to get data from dmi for %s\n", name);
 			return NULL;
 		}
 		info->irq = dev_data->instance;
@@ -155,7 +154,7 @@ static struct i2c_client *__add_probed_i2c_device(
 
 	adapter = i2c_get_adapter(bus);
 	if (!adapter) {
-		pr_err("%s failed to get i2c adapter %d.\n", __func__, bus);
+		pr_err("failed to get i2c adapter %d\n", bus);
 		return NULL;
 	}
 
@@ -174,19 +173,18 @@ static struct i2c_client *__add_probed_i2c_device(
 		dummy = i2c_new_probed_device(adapter, &dummy_info,
 					      alt_addr_list, NULL);
 		if (dummy) {
-			pr_debug("%s %d-%02x is probed at %02x\n",
-				  __func__, bus, info->addr, dummy->addr);
+			pr_debug("%d-%02x is probed at %02x\n",
+				 bus, info->addr, dummy->addr);
 			i2c_unregister_device(dummy);
 			client = i2c_new_device(adapter, info);
 		}
 	}
 
 	if (!client)
-		pr_notice("%s failed to register device %d-%02x\n",
-			  __func__, bus, info->addr);
+		pr_notice("failed to register device %d-%02x\n",
+			  bus, info->addr);
 	else
-		pr_debug("%s added i2c device %d-%02x\n",
-			 __func__, bus, info->addr);
+		pr_debug("added i2c device %d-%02x\n", bus, info->addr);
 
 	i2c_put_adapter(adapter);
 	return client;
@@ -227,7 +225,7 @@ static int find_i2c_adapter_num(enum i2c_adapter_type type)
 	dev = bus_find_device(&i2c_bus_type, NULL, &lookup, __find_i2c_adap);
 	if (!dev) {
 		/* Adapters may appear later. Deferred probing will retry */
-		pr_notice("%s: i2c adapter %s not found on system.\n", __func__,
+		pr_notice("i2c adapter %s not found on system.\n",
 			  lookup.name);
 		return -ENODEV;
 	}
@@ -349,7 +347,7 @@ static int setup_tsl2563_als(enum i2c_adapter_type type)
 static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
 {
 	cros_laptop = (void *)id->driver_data;
-	pr_debug("DMI Matched %s.\n", id->ident);
+	pr_debug("DMI Matched %s\n", id->ident);
 
 	/* Indicate to dmi_scan that processing is done. */
 	return 1;
@@ -392,8 +390,7 @@ static int chromeos_laptop_probe(struct platform_device *pdev)
 				ret = -EPROBE_DEFER;
 			} else {
 				/* Ran out of tries. */
-				pr_notice("%s: Ran out of tries for device.\n",
-					  __func__);
+				pr_notice("ran out of tries for device.\n");
 				i2c_dev->state = TIMEDOUT;
 			}
 		} else {
@@ -600,7 +597,7 @@ static int __init chromeos_laptop_init(void)
 	int ret;
 
 	if (!dmi_check_system(chromeos_laptop_dmi_table)) {
-		pr_debug("%s unsupported system.\n", __func__);
+		pr_debug("unsupported system\n");
 		return -ENODEV;
 	}
 
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 05/14] platform/chrome: chromeos_laptop - stop setting suspend mode for Atmel devices
From: Dmitry Torokhov @ 2018-03-12 19:08 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Atmel touch controller driver no longer respects suspend mode specified in
platform data, so let's stop setting it.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 54a13c70e1d8f..0a43f1833de3f 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -100,7 +100,6 @@ 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,
-	.suspend_mode		= MXT_SUSPEND_T9_CTRL,
 };
 
 static struct i2c_board_info atmel_224s_tp_device = {
@@ -111,7 +110,6 @@ static struct i2c_board_info atmel_224s_tp_device = {
 
 static struct mxt_platform_data atmel_1664s_platform_data = {
 	.irqflags		= IRQF_TRIGGER_FALLING,
-	.suspend_mode		= MXT_SUSPEND_T9_CTRL,
 };
 
 static struct i2c_board_info atmel_1664s_device = {
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 04/14] platform/chrome: chromeos_laptop - add SPDX identifier
From: Dmitry Torokhov @ 2018-03-12 19:08 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Replace the original license statement with the SPDX identifier.
Add also one line of description as recommended by the COPYING file.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/platform/chrome/chromeos_laptop.c | 27 +++++------------------
 1 file changed, 5 insertions(+), 22 deletions(-)

diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index d8599736a41a2..54a13c70e1d8f 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -1,25 +1,8 @@
-/*
- *  chromeos_laptop.c - Driver to instantiate Chromebook i2c/smbus devices.
- *
- *  Author : Benson Leung <bleung@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
- *
- */
+// SPDX-License-Identifier: GPL-2.0+
+// Driver to instantiate Chromebook i2c/smbus devices.
+//
+// Copyright (C) 2012 Google, Inc.
+// Author: Benson Leung <bleung@chromium.org>
 
 #include <linux/dmi.h>
 #include <linux/i2c.h>
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 03/14] Input: atmel_mxt_ts - switch ChromeOS ACPI devices to generic props
From: Dmitry Torokhov @ 2018-03-12 19:08 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Move older ChromeOS devices describing Atmel controllers in ACPI, but not
providing enough details to configure the controllers properly, from
platform data over to generic device properties. This will allow us
remove support for platform data later on, leaving only generic device
properties in place.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 63 +++++++++++++++---------
 1 file changed, 40 insertions(+), 23 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 072b78d3c6e00..cf2aac4e79ae8 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2972,7 +2972,7 @@ mxt_parse_device_properties(struct i2c_client *client)
 
 struct mxt_acpi_platform_data {
 	const char *hid;
-	struct mxt_platform_data pdata;
+	const struct property_entry *props;
 };
 
 static unsigned int samus_touchpad_buttons[] = {
@@ -2982,14 +2982,16 @@ static unsigned int samus_touchpad_buttons[] = {
 	BTN_LEFT
 };
 
+static const struct property_entry samus_touchpad_props[] = {
+	PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons),
+	{ }
+};
+
 static struct mxt_acpi_platform_data samus_platform_data[] = {
 	{
 		/* Touchpad */
 		.hid	= "ATML0000",
-		.pdata	= {
-			.t19_num_keys	= ARRAY_SIZE(samus_touchpad_buttons),
-			.t19_keymap	= samus_touchpad_buttons,
-		},
+		.props	= samus_touchpad_props,
 	},
 	{
 		/* Touchscreen */
@@ -3007,14 +3009,16 @@ static unsigned int chromebook_tp_buttons[] = {
 	BTN_LEFT
 };
 
+static const struct property_entry chromebook_tp_props[] = {
+	PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_tp_buttons),
+	{ }
+};
+
 static struct mxt_acpi_platform_data chromebook_platform_data[] = {
 	{
 		/* Touchpad */
 		.hid	= "ATML0000",
-		.pdata	= {
-			.t19_num_keys	= ARRAY_SIZE(chromebook_tp_buttons),
-			.t19_keymap	= chromebook_tp_buttons,
-		},
+		.props	= chromebook_tp_props,
 	},
 	{
 		/* Touchscreen */
@@ -3044,7 +3048,7 @@ static const struct dmi_system_id mxt_dmi_table[] = {
 	{ }
 };
 
-static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client)
+static int mxt_acpi_probe(struct i2c_client *client)
 {
 	struct acpi_device *adev;
 	const struct dmi_system_id *system_id;
@@ -3061,33 +3065,46 @@ static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client)
 	 * as a threshold.
 	 */
 	if (client->addr < 0x40)
-		return ERR_PTR(-ENXIO);
+		return -ENXIO;
 
 	adev = ACPI_COMPANION(&client->dev);
 	if (!adev)
-		return ERR_PTR(-ENOENT);
+		return -ENOENT;
 
 	system_id = dmi_first_match(mxt_dmi_table);
 	if (!system_id)
-		return ERR_PTR(-ENOENT);
+		return -ENOENT;
 
 	acpi_pdata = system_id->driver_data;
 	if (!acpi_pdata)
-		return ERR_PTR(-ENOENT);
+		return -ENOENT;
 
 	while (acpi_pdata->hid) {
-		if (!strcmp(acpi_device_hid(adev), acpi_pdata->hid))
-			return &acpi_pdata->pdata;
+		if (!strcmp(acpi_device_hid(adev), acpi_pdata->hid)) {
+			/*
+			 * Remove previously installed properties if we
+			 * are probing this device not for the very first
+			 * time.
+			 */
+			device_remove_properties(&client->dev);
+
+			/*
+			 * Now install the platform-specific properties
+			 * that are missing from ACPI.
+			 */
+			device_add_properties(&client->dev, acpi_pdata->props);
+			break;
+		}
 
 		acpi_pdata++;
 	}
 
-	return ERR_PTR(-ENOENT);
+	return 0;
 }
 #else
-static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client)
+static int mxt_acpi_probe(struct i2c_client *client)
 {
-	return ERR_PTR(-ENOENT);
+	return -ENOENT;
 }
 #endif
 
@@ -3100,10 +3117,6 @@ mxt_get_platform_data(struct i2c_client *client)
 	if (pdata)
 		return pdata;
 
-	pdata = mxt_parse_acpi(client);
-	if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT)
-		return pdata;
-
 	return mxt_parse_device_properties(client);
 }
 
@@ -3113,6 +3126,10 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	const struct mxt_platform_data *pdata;
 	int error;
 
+	error = mxt_acpi_probe(client);
+	if (error && error != -ENOENT)
+		return error;
+
 	pdata = mxt_get_platform_data(client);
 	if (IS_ERR(pdata))
 		return PTR_ERR(pdata);
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 02/14] Input: atmel_mxt_ts - switch from OF to generic device properties
From: Dmitry Torokhov @ 2018-03-12 19:08 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

Instead of using OF-specific APIs to fecth device properties, let's switch
to generic device properties API. This will allow us to use device
properties on legacy ChromeOS devices and get rid of platform data down
the road.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 59 ++++++++++++------------
 1 file changed, 30 insertions(+), 29 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 1aabfae1297ba..072b78d3c6e00 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -29,6 +29,7 @@
 #include <linux/of.h>
 #include <linux/slab.h>
 #include <linux/gpio/consumer.h>
+#include <linux/property.h>
 #include <asm/unaligned.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
@@ -2920,47 +2921,52 @@ static void mxt_input_close(struct input_dev *dev)
 	mxt_stop(data);
 }
 
-#ifdef CONFIG_OF
-static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client)
+static const struct mxt_platform_data *
+mxt_parse_device_properties(struct i2c_client *client)
 {
+	static const char keymap_property[] = "linux,gpio-keymap";
 	struct mxt_platform_data *pdata;
-	struct device_node *np = client->dev.of_node;
 	u32 *keymap;
-	int proplen, ret;
-
-	if (!np)
-		return ERR_PTR(-ENOENT);
+	int n_keys;
+	int error;
 
 	pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
 	if (!pdata)
 		return ERR_PTR(-ENOMEM);
 
-	if (of_find_property(np, "linux,gpio-keymap", &proplen)) {
-		pdata->t19_num_keys = proplen / sizeof(u32);
+	if (device_property_present(&client->dev, keymap_property)) {
+		n_keys = device_property_read_u32_array(&client->dev,
+							keymap_property,
+							NULL, 0);
+		if (n_keys <= 0) {
+			error = n_keys < 0 ? n_keys : -EINVAL;
+			dev_err(&client->dev,
+				"invalid/malformed '%s' property: %d\n",
+				keymap_property, error);
+			return ERR_PTR(error);
+		}
 
-		keymap = devm_kzalloc(&client->dev,
-				pdata->t19_num_keys * sizeof(keymap[0]),
-				GFP_KERNEL);
+		keymap = devm_kmalloc_array(&client->dev, n_keys, sizeof(u32),
+					    GFP_KERNEL);
 		if (!keymap)
 			return ERR_PTR(-ENOMEM);
 
-		ret = of_property_read_u32_array(np, "linux,gpio-keymap",
-						 keymap, pdata->t19_num_keys);
-		if (ret)
-			dev_warn(&client->dev,
-				 "Couldn't read linux,gpio-keymap: %d\n", ret);
+		error = device_property_read_u32_array(&client->dev,
+						       keymap_property,
+						       keymap, n_keys);
+		if (error) {
+			dev_err(&client->dev,
+				"failed to parse '%s' property: %d\n",
+				keymap_property, error);
+			return ERR_PTR(error);
+		}
 
 		pdata->t19_keymap = keymap;
+		pdata->t19_num_keys = n_keys;
 	}
 
 	return pdata;
 }
-#else
-static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client)
-{
-	return ERR_PTR(-ENOENT);
-}
-#endif
 
 #ifdef CONFIG_ACPI
 
@@ -3094,16 +3100,11 @@ mxt_get_platform_data(struct i2c_client *client)
 	if (pdata)
 		return pdata;
 
-	pdata = mxt_parse_dt(client);
-	if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT)
-		return pdata;
-
 	pdata = mxt_parse_acpi(client);
 	if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT)
 		return pdata;
 
-	dev_err(&client->dev, "No platform data specified\n");
-	return ERR_PTR(-EINVAL);
+	return mxt_parse_device_properties(client);
 }
 
 static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id)
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 01/14] Input: atmel_mxt_ts - do not pass suspend mode in platform data
From: Dmitry Torokhov @ 2018-03-12 19:08 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel
In-Reply-To: <20180312190907.174301-1-dmitry.torokhov@gmail.com>

The way we are supposed to put controller to sleep and wake it up does not
depend on the platform, but rather on controller itself. Controllers using
T9 require manipulating T9 control register, while others, using newer
T100, should be put to sleep by adjusting T7 power config.

We'll keep pdata->suspend_mode for now and remove it when we rework
chromeos-laptop driver.

Signed-off-by: Dmitry Torokhov <dmitry.torokhov@gmail.com>
---
 drivers/input/touchscreen/atmel_mxt_ts.c | 15 ++++++---------
 1 file changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/input/touchscreen/atmel_mxt_ts.c b/drivers/input/touchscreen/atmel_mxt_ts.c
index 7659bc48f1db8..1aabfae1297ba 100644
--- a/drivers/input/touchscreen/atmel_mxt_ts.c
+++ b/drivers/input/touchscreen/atmel_mxt_ts.c
@@ -2868,8 +2868,8 @@ static const struct attribute_group mxt_attr_group = {
 
 static void mxt_start(struct mxt_data *data)
 {
-	switch (data->pdata->suspend_mode) {
-	case MXT_SUSPEND_T9_CTRL:
+	switch (data->multitouch) {
+	case MXT_TOUCH_MULTI_T9:
 		mxt_soft_reset(data);
 
 		/* Touch enable */
@@ -2878,7 +2878,7 @@ static void mxt_start(struct mxt_data *data)
 				MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0x83);
 		break;
 
-	case MXT_SUSPEND_DEEP_SLEEP:
+	case MXT_TOUCH_MULTITOUCHSCREEN_T100:
 	default:
 		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_RUN);
 
@@ -2886,19 +2886,18 @@ static void mxt_start(struct mxt_data *data)
 		mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false);
 		break;
 	}
-
 }
 
 static void mxt_stop(struct mxt_data *data)
 {
-	switch (data->pdata->suspend_mode) {
-	case MXT_SUSPEND_T9_CTRL:
+	switch (data->multitouch) {
+	case MXT_TOUCH_MULTI_T9:
 		/* Touch disable */
 		mxt_write_object(data,
 				MXT_TOUCH_MULTI_T9, MXT_T9_CTRL, 0);
 		break;
 
-	case MXT_SUSPEND_DEEP_SLEEP:
+	case MXT_TOUCH_MULTITOUCHSCREEN_T100:
 	default:
 		mxt_set_t7_power_cfg(data, MXT_POWER_CFG_DEEPSLEEP);
 		break;
@@ -2954,8 +2953,6 @@ static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client)
 		pdata->t19_keymap = keymap;
 	}
 
-	pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP;
-
 	return pdata;
 }
 #else
-- 
2.16.2.660.g709887971b-goog

^ permalink raw reply related

* [PATCH 00/14] chrome_laptop: stop being a platform driver
From: Dmitry Torokhov @ 2018-03-12 19:08 UTC (permalink / raw)
  To: linux-input, Benson Leung; +Cc: Nick Dyer, Olof Johansson, linux-kernel

Hi,

This series is a combination of Atmel touchscreen driver stopping using
platform data and moving over to generic device properties, and
chromeos-laptop switching from being platform driver, which is the wrong
abstraction for it, and moving to using i2c bis notifier. Switching from
platform driver to the notifiers allows us to get rid of the ugly code that
manually tries to handle deferrals in case i2c bus is not ready at the time
we start initializing the module.

Benson, because chromeos-laptop is instantiating Atmel devices the 2
changes are intertwined. While we could apply them in stages, with parts
going through input and parts going through your tree I was wondering if we
could speed up the process and push the series through one or another tree
(if you are OK with the patches, of course).

Thanks!

Dmitry Torokhov (14):
  Input: atmel_mxt_ts - do not pass suspend mode in platform data
  Input: atmel_mxt_ts - switch from OF to generic device properties
  Input: atmel_mxt_ts - switch ChromeOS ACPI devices to generic props
  platform/chrome: chromeos_laptop - add SPDX identifier
  platform/chrome: chromeos_laptop - stop setting suspend mode for Atmel devices
  platform/chrome: chromeos_laptop - introduce pr_fmt()
  platform/chrome: chromeos_laptop - factor out getting IRQ from DMI
  platform/chrome: chromeos_laptop - rework i2c peripherals initialization
  platform/chrome: chromeos_laptop - parse DMI IRQ data once
  platform/chrome: chromeos_laptop - use I2C notifier to create devices
  platform/chrome: chromeos_laptop - rely on I2C to set up interrupt trigger
  platform/chrome: chromeos_laptop - use device properties for Pixel
  platform/chrome: chromeos_laptop - discard data for unneeded boards
  Input: atmel_mxt_ts - remove platform data support

 MAINTAINERS                                |   1 -
 drivers/input/touchscreen/atmel_mxt_ts.c   | 216 +++--
 drivers/platform/chrome/chromeos_laptop.c  | 896 +++++++++++----------
 include/linux/platform_data/atmel_mxt_ts.h |  31 -
 4 files changed, 559 insertions(+), 585 deletions(-)
 delete mode 100644 include/linux/platform_data/atmel_mxt_ts.h

-- 
Dmitry

^ permalink raw reply

* Re: [PATCH v5 00/36] DRM Rockchip rk3399 (Kevin)
From: Heiko Stübner @ 2018-03-12 17:27 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: airlied, dri-devel, thierry.reding, Laurent.pinchart, ykk, kernel,
	m.szyprowski, linux-samsung-soc, rydberg, krzk, linux-rockchip,
	kgene, linux-input, orjan.eide, wxt, linux-kernel, jeffy.chen,
	linux-arm-kernel, mark.yao, wzz, hl, jingoohan1, sw0312.kim,
	dianders, tfiga, kyungmin.park, kuankuan.y, hshi
In-Reply-To: <20180309222327.18689-1-enric.balletbo@collabora.com>

Am Freitag, 9. März 2018, 23:22:51 CET schrieb Enric Balletbo i Serra:
> Hi,
> 
> This patchset includes cleanups, improvements, and bug fixes for
> Rockchip DRM driver and PSR support.
> 
> This new version is the same as before removing some of the patches
> already applied and fixing the Exynos issue due patch '[v4 15/38]
> drm/bridge: analogix_dp: Ensure edp is disabled when shutting down
> the panel' reported by Marek.

The series on both rk3288 (without psr) and rk3399 (with psr)
Tested-by: Heiko Stuebner <heiko@sntech.de>


I've tried reviewing at least the Rockchip parts, so if  bridge-
maintainers are going to apply patches to drm-misc they could
pick up the interlinked Rockchip patches as well.

I don't think it's necessary to wait for the full series to be mergeable
and before I just picked things from the beginning that looked ready
and worked, so I guess continuing this way could help making that
chunk of patches smaller :-) .


Heiko
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v5 19/36] drm/rockchip: Restore psr->state when enable/disable psr failed
From: Heiko Stübner @ 2018-03-12 17:06 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: airlied, dri-devel, thierry.reding, Laurent.pinchart, ykk, kernel,
	m.szyprowski, linux-samsung-soc, rydberg, krzk, linux-rockchip,
	kgene, linux-input, orjan.eide, wxt, linux-kernel, jeffy.chen,
	linux-arm-kernel, mark.yao, wzz, hl, jingoohan1, sw0312.kim,
	dianders, tfiga, kyungmin.park, kuankuan.y, hshi
In-Reply-To: <20180309222327.18689-20-enric.balletbo@collabora.com>

Am Freitag, 9. März 2018, 23:23:10 CET schrieb Enric Balletbo i Serra:
> From: zain wang <wzz@rock-chips.com>
> 
> If we failed disable psr, it would hang the display until next psr
> cycle coming. So we should restore psr->state when it failed.
> 
> Cc: Tomasz Figa <tfiga@chromium.org>
> Signed-off-by: zain wang <wzz@rock-chips.com>
> Signed-off-by: Douglas Anderson <dianders@chromium.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

Reviewed-by: Heiko Stuebner <heiko@sntech.de>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v5 03/36] drm/bridge: analogix_dp: Don't change psr while bridge is disabled
From: Heiko Stübner @ 2018-03-12 17:02 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: airlied, dri-devel, thierry.reding, Laurent.pinchart, ykk, kernel,
	m.szyprowski, linux-samsung-soc, rydberg, krzk, linux-rockchip,
	kgene, linux-input, orjan.eide, wxt, linux-kernel, jeffy.chen,
	linux-arm-kernel, mark.yao, wzz, hl, Tomeu Vizoso, jingoohan1,
	sw0312.kim, dianders, tfiga, kyungmin.park, kuankuan.y, hshi
In-Reply-To: <20180309222327.18689-4-enric.balletbo@collabora.com>

Am Freitag, 9. März 2018, 23:22:54 CET schrieb Enric Balletbo i Serra:
> From: zain wang <wzz@rock-chips.com>
> 
> There is a race between AUX CH bring-up and enabling bridge which will
> cause link training to fail. To avoid hitting it, don't change psr state
> while enabling the bridge.
> 
> Cc: Tomeu Vizoso <tomeu.vizoso@collabora.com>
> Cc: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: zain wang <wzz@rock-chips.com>
> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
> [seanpaul fixed up the commit message a bit and renamed *_supported to
> *_enabled] Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

Reviewed-by: Heiko Stuebner <heiko@sntech.de>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v5 01/36] drm/bridge: analogix_dp: detect Sink PSR state after configuring the PSR
From: Heiko Stübner @ 2018-03-12 17:00 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: airlied, dri-devel, thierry.reding, Laurent.pinchart, ykk, kernel,
	m.szyprowski, linux-samsung-soc, rydberg, krzk, linux-rockchip,
	kgene, linux-input, orjan.eide, wxt, linux-kernel, jeffy.chen,
	Stéphane Marchesin, linux-arm-kernel, mark.yao, wzz, hl,
	jingoohan1, sw0312.kim, dianders, tfiga, kyungmin.park,
	kuankuan.y, hshi
In-Reply-To: <20180309222327.18689-2-enric.balletbo@collabora.com>

Am Freitag, 9. März 2018, 23:22:52 CET schrieb Enric Balletbo i Serra:
> From: Yakir Yang <ykk@rock-chips.com>
> 
> Make sure the request PSR state takes effect in analogix_dp_send_psr_spd()
> function, or print the sink PSR error state if we failed to apply the
> requested PSR setting.
> 
> Cc: 征增 王 <wzz@rock-chips.com>
> Cc: Stéphane Marchesin <marcheu@chromium.org>
> Signed-off-by: Yakir Yang <ykk@rock-chips.com>
> [seanpaul changed timeout loop to a readx poll]
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

Reviewed-by: Heiko Stuebner <heiko@sntech.de>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v5 06/36] drm/rockchip: Only wait for panel ACK on PSR entry
From: Heiko Stübner @ 2018-03-12 16:58 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: airlied, dri-devel, thierry.reding, Laurent.pinchart, ykk, kernel,
	m.szyprowski, linux-samsung-soc, rydberg, krzk, linux-rockchip,
	kgene, linux-input, orjan.eide, wxt, linux-kernel, jeffy.chen,
	Stéphane Marchesin, Sonny Rao, linux-arm-kernel, mark.yao,
	wzz, hl, jingoohan1, sw0312.kim, dianders, tfiga, kyungmin.park,
	kuankuan.y, hshi
In-Reply-To: <20180309222327.18689-7-enric.balletbo@collabora.com>

Hi,

the subject is misleading I think, as this is touching only the generic
bridge code and not anything Rockchip-related, so should probably
be "drm/bridge"?

Am Freitag, 9. März 2018, 23:22:57 CET schrieb Enric Balletbo i Serra:
> From: zain wang <wzz@rock-chips.com>
> 
> We currently wait for the panel to mirror our intended PSR state
> before continuing on both PSR enter and PSR exit. This is really
> only important to do when we're entering PSR, since we want to
> be sure the last frame we pushed is being served from the panel's
> internal fb before shutting down the soc blocks (vop/analogix).
> 
> This patch changes the behavior such that we only wait for the
> panel to complete the PSR transition when we're entering PSR, and
> to skip verification when we're exiting.
> 
> Cc: Stéphane Marchesin <marcheu@chromium.org>
> Cc: Sonny Rao <sonnyrao@chromium.org>
> Signed-off-by: zain wang <wzz@rock-chips.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

change itself looks good, so
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v5 04/36] drm/rockchip: add mutex vop lock
From: Heiko Stübner @ 2018-03-12 16:29 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: airlied, dri-devel, thierry.reding, Laurent.pinchart, ykk, kernel,
	m.szyprowski, linux-samsung-soc, rydberg, krzk, linux-rockchip,
	kgene, linux-input, orjan.eide, wxt, linux-kernel, jeffy.chen,
	linux-arm-kernel, mark.yao, wzz, hl, jingoohan1, sw0312.kim,
	dianders, tfiga, kyungmin.park, kuankuan.y, hshi
In-Reply-To: <20180309222327.18689-5-enric.balletbo@collabora.com>

Am Freitag, 9. März 2018, 23:22:55 CET schrieb Enric Balletbo i Serra:
> From: zain wang <wzz@rock-chips.com>
> 
> Add a lock to vop to avoid disabling the crtc while waiting for a line
> flag while enabling psr. If we disable in the middle of waiting for the
> line flag, we'll end up timing out or worse.
> 
> Signed-off-by: zain wang <wzz@rock-chips.com>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

Reviewed-by: Heiko Stuebner <heiko@sntech.de>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v5 02/36] drm/rockchip: Remove analogix psr worker
From: Heiko Stübner @ 2018-03-12 16:26 UTC (permalink / raw)
  To: Enric Balletbo i Serra
  Cc: airlied, dri-devel, thierry.reding, Laurent.pinchart, ykk, kernel,
	m.szyprowski, linux-samsung-soc, rydberg, krzk, linux-rockchip,
	kgene, linux-input, orjan.eide, wxt, linux-kernel, jeffy.chen,
	Stéphane Marchesin, linux-arm-kernel, mark.yao, wzz, hl,
	jingoohan1, sw0312.kim, dianders, tfiga, kyungmin.park,
	kuankuan.y, hshi
In-Reply-To: <20180309222327.18689-3-enric.balletbo@collabora.com>

Am Freitag, 9. März 2018, 23:22:53 CET schrieb Enric Balletbo i Serra:
> From: Sean Paul <seanpaul@chromium.org>
> 
> Now that the spinlocks and timers are gone, we can remove the psr
> worker located in rockchip's analogix driver and do the enable/disable
> directly. This should simplify the code and remove races on disable.
> 
> Cc: 征增 王 <wzz@rock-chips.com>
> Cc: Stéphane Marchesin <marcheu@chromium.org>
> Signed-off-by: Sean Paul <seanpaul@chromium.org>
> Signed-off-by: Thierry Escande <thierry.escande@collabora.com>
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> Tested-by: Marek Szyprowski <m.szyprowski@samsung.com>

Reviewed-by: Heiko Stuebner <heiko@sntech.de>
_______________________________________________
dri-devel mailing list
dri-devel@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/dri-devel

^ permalink raw reply

* Re: [PATCH v2 2/4] mfd: add Gateworks System Controller core driver
From: Lee Jones @ 2018-03-12 14:41 UTC (permalink / raw)
  To: Tim Harvey
  Cc: Rob Herring, Mark Rutland, Mark Brown, Dmitry Torokhov,
	linux-kernel, devicetree, linux-arm-kernel, linux-hwmon,
	linux-input, Randy Dunlap
In-Reply-To: <1520287361-12569-3-git-send-email-tharvey@gateworks.com>

On Mon, 05 Mar 2018, Tim Harvey wrote:

> The Gateworks System Controller (GSC) is an I2C slave controller
> implemented with an MSP430 micro-controller whose firmware embeds the
> following features:
>  - I/O expander (16 GPIO's) using PCA955x protocol
>  - Real Time Clock using DS1672 protocol
>  - User EEPROM using AT24 protocol
>  - HWMON using custom protocol
>  - Interrupt controller with tamper detect, user pushbotton
>  - Watchdog controller capable of full board power-cycle
>  - Power Control capable of full board power-cycle
> 
> see http://trac.gateworks.com/wiki/gsc for more details
> 
> Cc: Randy Dunlap <rdunlap@infradead.org>
> Signed-off-by: Tim Harvey <tharvey@gateworks.com>
> ---
> v2:
> - change license comment block style
> - remove COMPILE_TEST (Randy)
> - fixed whitespace issues
> - replaced a printk with dev_err
> 
>  drivers/mfd/Kconfig     |  13 ++
>  drivers/mfd/Makefile    |   1 +
>  drivers/mfd/gsc.c       | 330 ++++++++++++++++++++++++++++++++++++++++++++++++

I'd prefer gateworks-sc.c

>  include/linux/mfd/gsc.h |  82 ++++++++++++
>  4 files changed, 426 insertions(+)
>  create mode 100644 drivers/mfd/gsc.c
>  create mode 100644 include/linux/mfd/gsc.h
> 
> diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
> index 1d20a80..5694013 100644
> --- a/drivers/mfd/Kconfig
> +++ b/drivers/mfd/Kconfig
> @@ -341,6 +341,19 @@ config MFD_EXYNOS_LPASS
>  	  Select this option to enable support for Samsung Exynos Low Power
>  	  Audio Subsystem.
>  
> +config MFD_GSC

Prefer MFD_GATEWORKS_SC

> +	tristate "Gateworks System Controller"
> +	depends on (I2C && OF)
> +	select MFD_CORE
> +	select REGMAP_I2C
> +	select REGMAP_IRQ
> +	help
> +	  Enable support for the Gateworks System Controller found
> +	  on Gateworks Single Board Computers.
> +
> +	  To compile this driver as a module, choose M here: the
> +	  module will be called gsc.
> +
>  config MFD_MC13XXX
>  	tristate
>  	depends on (SPI_MASTER || I2C)
> diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
> index d9474ad..aede0bc 100644
> --- a/drivers/mfd/Makefile
> +++ b/drivers/mfd/Makefile
> @@ -18,6 +18,7 @@ obj-$(CONFIG_MFD_CROS_EC)	+= cros_ec_core.o
>  obj-$(CONFIG_MFD_CROS_EC_I2C)	+= cros_ec_i2c.o
>  obj-$(CONFIG_MFD_CROS_EC_SPI)	+= cros_ec_spi.o
>  obj-$(CONFIG_MFD_EXYNOS_LPASS)	+= exynos-lpass.o
> +obj-$(CONFIG_MFD_GSC)		+= gsc.o
>  
>  rtsx_pci-objs			:= rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
>  obj-$(CONFIG_MFD_RTSX_PCI)	+= rtsx_pci.o
> diff --git a/drivers/mfd/gsc.c b/drivers/mfd/gsc.c
> new file mode 100644
> index 0000000..4ac400a
> --- /dev/null
> +++ b/drivers/mfd/gsc.c
> @@ -0,0 +1,330 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * Copyright (C) 2018 Gateworks Corporation
> + *
> + * The Gateworks System Controller (GSC) is a family of a multi-function
> + * "Power Management and System Companion Device" chips originally designed for
> + * use in Gateworks Single Board Computers. The control interface is I2C,
> + * at 100kbps, with an interrupt.
> + *
> + */
> +#include <linux/device.h>
> +#include <linux/i2c.h>
> +#include <linux/interrupt.h>
> +#include <linux/mfd/core.h>

What's this for?

> +#include <linux/mfd/gsc.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/regmap.h>
> +
> +/*
> + * The GSC suffers from an errata where occasionally during
> + * ADC cycles the chip can NAK i2c transactions. To ensure we have reliable

s/i2c/I2C/

> + * register access we place retries around register access.
> + */
> +#define I2C_RETRIES	3
> +
> +static int gsc_regmap_regwrite(void *context, unsigned int reg,
> +			       unsigned int val)
> +{
> +	struct i2c_client *client = context;
> +	int retry, ret;
> +
> +	for (retry = 0; retry < I2C_RETRIES; retry++) {
> +		ret = i2c_smbus_write_byte_data(client, reg, val);
> +		/*
> +		 * -EAGAIN returned when the i2c host controller is busy
> +		 * -EIO returned when i2c device is busy
> +		 */
> +		if (ret != -EAGAIN && ret != -EIO)
> +			break;
> +	}
> +	if (ret < 0) {
> +		dev_err(&client->dev, ">> 0x%02x %d\n", reg, ret);

">>" doesn't tell the user much.  To the unaware you are spitting out
random characters/values.  Please provide more information in your
error messages.


> +		return ret;
> +	}
> +	dev_dbg(&client->dev, ">> 0x%02x=0x%02x (%d)\n", reg, val, retry);

As above.  Or better still, consider removing this line completely.

> +	return 0;
> +}
> +
> +static int gsc_regmap_regread(void *context, unsigned int reg,
> +			      unsigned int *val)
> +{
> +	struct i2c_client *client = context;
> +	int retry, ret;
> +
> +	for (retry = 0; retry < I2C_RETRIES; retry++) {
> +		ret = i2c_smbus_read_byte_data(client, reg);
> +		/*
> +		 * -EAGAIN returned when the i2c host controller is busy
> +		 * -EIO returned when i2c device is busy
> +		 */
> +		if (ret != -EAGAIN && ret != -EIO)
> +			break;
> +	}
> +	if (ret < 0) {
> +		dev_err(&client->dev, "<< 0x%02x %d\n", reg, ret);

As above.

> +		return ret;
> +	}
> +
> +	*val = ret & 0xff;
> +	dev_dbg(&client->dev, "<< 0x%02x=0x%02x (%d)\n", reg, *val, retry);

As above.

> +	return 0;
> +}
> +
> +static struct regmap_bus regmap_gsc = {
> +	.reg_write = gsc_regmap_regwrite,
> +	.reg_read = gsc_regmap_regread,
> +};
> +
> +/*
> + * gsc_powerdown - API to use GSC to power down board for a specific time
> + *
> + * secs - number of seconds to remain powered off
> + */
> +static int gsc_powerdown(struct gsc_dev *gsc, unsigned long secs)
> +{
> +	int ret;
> +	unsigned char regs[4];
> +
> +	dev_info(&gsc->i2c->dev, "GSC powerdown for %ld seconds\n",
> +		 secs);
> +	regs[0] = secs & 0xff;
> +	regs[1] = (secs >> 8) & 0xff;
> +	regs[2] = (secs >> 16) & 0xff;
> +	regs[3] = (secs >> 24) & 0xff;
> +	ret = regmap_bulk_write(gsc->regmap, GSC_TIME_ADD, regs, 4);
> +
> +	return ret;
> +}
> +
> +/*
> + * sysfs hooks
> + */

This comment is superfluous since we know what _show & _store functions
do.

> +static ssize_t gsc_show(struct device *dev, struct device_attribute *attr,
> +			char *buf)
> +{
> +	struct gsc_dev *gsc = dev_get_drvdata(dev);
> +	const char *name = attr->attr.name;
> +	int rz = 0;
> +
> +	if (strcasecmp(name, "fw_version") == 0)
> +		rz = sprintf(buf, "%d\n", gsc->fwver);
> +	else if (strcasecmp(name, "fw_crc") == 0)
> +		rz = sprintf(buf, "0x%04x\n", gsc->fwcrc);
> +
> +	return rz;
> +}
> +
> +static ssize_t gsc_store(struct device *dev, struct device_attribute *attr,
> +			 const char *buf, size_t count)
> +{
> +	struct gsc_dev *gsc = dev_get_drvdata(dev);
> +	const char *name = attr->attr.name;
> +	int ret;
> +
> +	if (strcasecmp(name, "powerdown") == 0) {
> +		long value;
> +
> +		ret = kstrtol(buf, 0, &value);
> +		if (ret == 0)
> +			gsc_powerdown(gsc, value);
> +	} else
> +		dev_err(dev, "invalid name '%s\n", name);
> +
> +	return count;
> +}
> +
> +

Please remove 2nd '\n'.

> +/*
> + * Create a group of attributes so that we can create and destroy them all
> + * at once.
> + */

No need for this comment.

> +static struct device_attribute attr_fwver =
> +	__ATTR(fw_version, 0440, gsc_show, NULL);
> +static struct device_attribute attr_fwcrc =
> +	__ATTR(fw_crc, 0440, gsc_show, NULL);
> +static struct device_attribute attr_pwrdown =
> +	__ATTR(powerdown, 0220, NULL, gsc_store);
> +
> +static struct attribute *gsc_attrs[] = {
> +	&attr_fwver.attr,
> +	&attr_fwcrc.attr,
> +	&attr_pwrdown.attr,
> +	NULL,
> +};
> +
> +static struct attribute_group attr_group = {
> +	.attrs = gsc_attrs,
> +};
> +
> +static const struct i2c_device_id gsc_i2c_ids[] = {
> +	{ "gsc_v1", gsc_v1 },
> +	{ "gsc_v2", gsc_v2 },
> +	{ "gsc_v3", gsc_v3 },
> +	{ },
> +};
> +
> +static const struct of_device_id gsc_of_match[] = {
> +	{ .compatible = "gw,gsc_v1", .data = (void *)gsc_v1 },
> +	{ .compatible = "gw,gsc_v2", .data = (void *)gsc_v2 },
> +	{ .compatible = "gw,gsc_v3", .data = (void *)gsc_v3 },
> +	{ }
> +};
> +
> +static const struct regmap_config gsc_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.cache_type = REGCACHE_NONE,
> +	.max_register = 0xf,
> +};
> +
> +static const struct regmap_config gsc_regmap_hwmon_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +	.cache_type = REGCACHE_NONE,
> +	.max_register = 0x37,
> +};
> +
> +static const struct regmap_irq gsc_irqs[] = {
> +	REGMAP_IRQ_REG(GSC_IRQ_PB, 0, BIT(GSC_IRQ_PB)),
> +	REGMAP_IRQ_REG(GSC_IRQ_KEY_ERASED, 0, BIT(GSC_IRQ_KEY_ERASED)),
> +	REGMAP_IRQ_REG(GSC_IRQ_EEPROM_WP, 0, BIT(GSC_IRQ_EEPROM_WP)),
> +	REGMAP_IRQ_REG(GSC_IRQ_RESV, 0, BIT(GSC_IRQ_RESV)),
> +	REGMAP_IRQ_REG(GSC_IRQ_GPIO, 0, BIT(GSC_IRQ_GPIO)),
> +	REGMAP_IRQ_REG(GSC_IRQ_TAMPER, 0, BIT(GSC_IRQ_TAMPER)),
> +	REGMAP_IRQ_REG(GSC_IRQ_WDT_TIMEOUT, 0, BIT(GSC_IRQ_WDT_TIMEOUT)),
> +	REGMAP_IRQ_REG(GSC_IRQ_SWITCH_HOLD, 0, BIT(GSC_IRQ_SWITCH_HOLD)),
> +};
> +
> +static const struct regmap_irq_chip gsc_irq_chip = {
> +	.name = KBUILD_MODNAME,

Please just type the name like "name".

> +	.irqs = gsc_irqs,
> +	.num_irqs = ARRAY_SIZE(gsc_irqs),
> +	.num_regs = 1,
> +	.status_base = GSC_IRQ_STATUS,
> +	.mask_base = GSC_IRQ_ENABLE,
> +	.mask_invert = true,
> +	.ack_base = GSC_IRQ_STATUS,
> +	.ack_invert = true,
> +};
> +
> +static int gsc_of_probe(struct device_node *np, struct gsc_dev *gsc)
> +{
> +	const struct of_device_id *of_id;
> +
> +	if (!np)
> +		return -ENODEV;
> +
> +	of_id = of_match_device(gsc_of_match, gsc->dev);
> +	if (of_id)
> +		gsc->type = (enum gsc_type)of_id->data;

Isn't there any way that you can fetch version information from the
device?

What is this value/information actually used for?

> +	return 0;
> +}
> +
> +static int
> +gsc_probe(struct i2c_client *client, const struct i2c_device_id *id)
> +{
> +	struct device *dev = &client->dev;
> +	struct gsc_dev *gsc;
> +	int ret;
> +	unsigned int reg;
> +
> +	gsc = devm_kzalloc(dev, sizeof(*gsc), GFP_KERNEL);
> +	if (!gsc)
> +		return -ENOMEM;
> +
> +	gsc->dev = &client->dev;
> +	gsc->i2c = client;
> +	gsc->irq = client->irq;
> +	i2c_set_clientdata(client, gsc);
> +
> +	gsc->regmap = devm_regmap_init(dev, &regmap_gsc, client,
> +				       &gsc_regmap_config);
> +	if (IS_ERR(gsc->regmap))
> +		return PTR_ERR(gsc->regmap);
> +
> +	ret = gsc_of_probe(dev->of_node, gsc);
> +	if (reg < 0)
> +		return ret;
> +
> +	if (regmap_read(gsc->regmap, GSC_FW_VER, &reg))
> +		return -EIO;
> +	gsc->fwver = reg;

'\n' here.

> +	regmap_read(gsc->regmap, GSC_FW_CRC, &reg);
> +	gsc->fwcrc = reg;
> +	regmap_read(gsc->regmap, GSC_FW_CRC + 1, &reg);
> +	gsc->fwcrc |= reg << 8;
> +
> +	gsc->i2c_hwmon = i2c_new_dummy(client->adapter, GSC_HWMON);
> +	if (!gsc->i2c_hwmon) {
> +		dev_err(dev, "Failed to allocate I2C device for HWMON\n");
> +		return -ENODEV;
> +	}
> +	i2c_set_clientdata(gsc->i2c_hwmon, gsc);
> +
> +	gsc->regmap_hwmon = devm_regmap_init(dev, &regmap_gsc, gsc->i2c_hwmon,
> +					     &gsc_regmap_hwmon_config);
> +	if (IS_ERR(gsc->regmap_hwmon)) {
> +		ret = PTR_ERR(gsc->regmap_hwmon);
> +		dev_err(dev, "failed to allocate register map: %d\n", ret);
> +		goto err_regmap;
> +	}
> +
> +	ret = devm_regmap_add_irq_chip(dev, gsc->regmap, gsc->irq,
> +				       IRQF_ONESHOT | IRQF_SHARED |
> +				       IRQF_TRIGGER_FALLING, 0,
> +				       &gsc_irq_chip, &gsc->irq_chip_data);
> +	if (ret)
> +		goto err_regmap;
> +
> +	dev_info(dev, "Gateworks System Controller v%d: fw v%02d 0x%04x\n",
> +		 gsc->type, gsc->fwver, gsc->fwcrc);
> +
> +	/* sysfs hooks */

Remove this comment please.

> +	ret = sysfs_create_group(&dev->kobj, &attr_group);
> +	if (ret)
> +		dev_err(dev, "failed to create sysfs attrs\n");
> +
> +	ret = of_platform_populate(dev->of_node, NULL, NULL, dev);
> +	if (ret)
> +		goto err_sysfs;
> +
> +	return 0;
> +
> +err_sysfs:
> +	sysfs_remove_group(&dev->kobj, &attr_group);
> +err_regmap:
> +	i2c_unregister_device(gsc->i2c_hwmon);
> +
> +	return ret;
> +}
> +
> +static int gsc_remove(struct i2c_client *client)
> +{
> +	sysfs_remove_group(&client->dev.kobj, &attr_group);

i2c_unregister_device()?

> +	return 0;
> +}
> +
> +static struct i2c_driver gsc_driver = {
> +	.driver = {
> +		.name	= KBUILD_MODNAME,

Just type the name please: "name".

> +		.of_match_table = of_match_ptr(gsc_of_match),
> +	},
> +	.probe		= gsc_probe,
> +	.remove		= gsc_remove,
> +	.id_table	= gsc_i2c_ids,
> +};
> +
> +module_i2c_driver(gsc_driver);
> +
> +MODULE_AUTHOR("Tim Harvey <tharvey@gateworks.com>");
> +MODULE_DESCRIPTION("I2C Core interface for GSC");
> +MODULE_LICENSE("GPL v2");
> diff --git a/include/linux/mfd/gsc.h b/include/linux/mfd/gsc.h
> new file mode 100644
> index 0000000..e0d8c8f
> --- /dev/null
> +++ b/include/linux/mfd/gsc.h
> @@ -0,0 +1,82 @@
> +/* SPDX-License-Identifier: GPL-2.0
> + *
> + * Copyright (C) 2018 Gateworks Corporation
> + */
> +#ifndef __LINUX_MFD_GSC_H_
> +#define __LINUX_MFD_GSC_H_
> +
> +/* Device Addresses */
> +#define GSC_MISC	0x20
> +#define GSC_UPDATE	0x21
> +#define GSC_GPIO	0x23
> +#define GSC_HWMON	0x29
> +#define GSC_EEPROM0	0x50
> +#define GSC_EEPROM1	0x51
> +#define GSC_EEPROM2	0x52
> +#define GSC_EEPROM3	0x53
> +#define GSC_RTC		0x68
> +
> +/* Register offsets */
> +#define GSC_CTRL_0	0x00
> +#define GSC_CTRL_1	0x01
> +#define GSC_TIME	0x02
> +#define GSC_TIME_ADD	0x06
> +#define GSC_IRQ_STATUS	0x0A
> +#define GSC_IRQ_ENABLE	0x0B
> +#define GSC_FW_CRC	0x0C
> +#define GSC_FW_VER	0x0E
> +#define GSC_WP		0x0F
> +
> +/* Bit definitions */
> +#define GSC_CTRL_0_PB_HARD_RESET	0
> +#define GSC_CTRL_0_PB_CLEAR_SECURE_KEY	1
> +#define GSC_CTRL_0_PB_SOFT_POWER_DOWN	2
> +#define GSC_CTRL_0_PB_BOOT_ALTERNATE	3
> +#define GSC_CTRL_0_PERFORM_CRC		4
> +#define GSC_CTRL_0_TAMPER_DETECT	5
> +#define GSC_CTRL_0_SWITCH_HOLD		6
> +
> +#define GSC_CTRL_1_SLEEP_ENABLE		0
> +#define GSC_CTRL_1_ACTIVATE_SLEEP	1
> +#define GSC_CTRL_1_LATCH_SLEEP_ADD	2
> +#define GSC_CTRL_1_SLEEP_NOWAKEPB	3
> +#define GSC_CTRL_1_WDT_TIME		4
> +#define GSC_CTRL_1_WDT_ENABLE		5
> +#define GSC_CTRL_1_SWITCH_BOOT_ENABLE	6
> +#define GSC_CTRL_1_SWITCH_BOOT_CLEAR	7
> +
> +#define GSC_IRQ_PB			0
> +#define GSC_IRQ_KEY_ERASED		1
> +#define GSC_IRQ_EEPROM_WP		2
> +#define GSC_IRQ_RESV			3
> +#define GSC_IRQ_GPIO			4
> +#define GSC_IRQ_TAMPER			5
> +#define GSC_IRQ_WDT_TIMEOUT		6
> +#define GSC_IRQ_SWITCH_HOLD		7
> +
> +/* Max registers */
> +#define GSC_HWMON_MAX_REG	56
> +
> +enum gsc_type {
> +	gsc_v1 = 1,
> +	gsc_v2 = 2,
> +	gsc_v3 = 3,
> +};
> +
> +struct gsc_dev {
> +	struct device *dev;
> +
> +	struct i2c_client *i2c;		/* 0x20: interrupt controller, WDT */
> +	struct i2c_client *i2c_hwmon;	/* 0x29: hwmon, fan controller */
> +
> +	struct regmap *regmap;
> +	struct regmap *regmap_hwmon;
> +	struct regmap_irq_chip_data *irq_chip_data;
> +
> +	int irq;
> +	enum gsc_type type;
> +	unsigned int fwver;
> +	unsigned short fwcrc;
> +};
> +
> +#endif /* __LINUX_MFD_GSC_H_ */

-- 
Lee Jones [李琼斯]
Linaro Services Technical Lead
Linaro.org │ Open source software for ARM SoCs
Follow Linaro: Facebook | Twitter | Blog

^ permalink raw reply

* Re: [PATCH v5 0/4] new driver for Valve Steam Controller
From: Clément VUCHENER @ 2018-03-12 14:30 UTC (permalink / raw)
  To: Rodrigo Rivas Costa
  Cc: Jiri Kosina, Benjamin Tissoires, Pierre-Loup A. Griffais,
	Cameron Gutman, lkml, linux-input
In-Reply-To: <20180311195842.5551-1-rodrigorivascosta@gmail.com>

2018-03-11 20:58 GMT+01:00 Rodrigo Rivas Costa <rodrigorivascosta@gmail.com>:
> This patchset implements a driver for Valve Steam Controller, based on a
> reverse analysis by myself.
>
> Sorry, I've been out of town for a few weeks and couldn't keep up with this...
>
> @Pierre-Loup and @Clément, could you please have another look at this and
> check if it is worthy? Benjamin will not commit it without an express ACK from
> Valve. Of course he is right to be cautious, but I checked this driver with
> the Steam Client and all seems to go just fine. I think that there is a lot of
> Linux out of the desktop that could use this driver and cannot use the Steam
> Client. Worst case scenario, this driver can now be blacklisted, but I hope
> that will not be needed.

I tested the driver with my 4.15 fedora kernel (I only built the
module not the whole kernel) and I got double inputs (your driver
input device + steam uinput device) when testing Shovel Knight with
Steam Big Picture. It seems to work fine when the inputs are the same,
but after changing the controller configuration in Steam, the issue
became apparent.

And without Steam and your external tool, you get double inputs too. I
tried RetroArch and it was unusable because of the keyboard inputs
from the lizard mode (e.g. pressing B also presses Esc and quits
RetroArch). Having to download and compile an external tool to make
the driver work properly may be too difficult for the user. Your goal
was to provide an alternative to user space drivers but now you
actually depend on (a very simple) one.

Also the button and axis codes do not match the gamepad API doc
(https://www.kernel.org/doc/Documentation/input/gamepad.txt).

>
> For full reference, I'm adding a full changelog of this patchset.
>
> Changes in v5:
>  * Fix license SPDX to GPL-2.0+.
>  * Minor stylistic changes (BIT(3) instead 0x08 and so on).
>
> Changes in v4:
>  * Add command to check the wireless connection status on probe, without
>    waiting for a message (thanks to Clément Vuchener for the tip).
>  * Removed the error code on redundant connection/disconnection messages. That
>    was harmless but polluted dmesg.
>  * Added buttons for touching the left-pad and right-pad.
>  * Fixed a misplaced #include from 2/4 to 1/4.
>
> Changes in v3:
>  * Use RCU to do the dynamic connec/disconnect of wireless devices.
>  * Remove entries in hid-quirks.c as they are no longer needed. This allows
>    this module to be blacklisted without side effects.
>  * Do not bypass the virtual keyboard/mouse HID devices to avoid breaking
>    existing use cases (lizard mode). A user-space tool to do that is
>    linked.
>  * Fully separated axes for joystick and left-pad. As it happens.
>  * Add fuzz values for left/right pad axes, they are a little wiggly.
>
> Changes in v2:
>  * Remove references to USB. Now the interesting interfaces are selected by
>    looking for the ones with feature reports.
>  * Feature reports buffers are allocated with hid_alloc_report_buf().
>  * Feature report length is checked, to avoid overflows in case of
>    corrupt/malicius USB devices.
>  * Resolution added to the ABS axes.
>  * A lot of minor cleanups.
>
> Rodrigo Rivas Costa (4):
>   HID: add driver for Valve Steam Controller
>   HID: steam: add serial number information.
>   HID: steam: command to check wireless connection
>   HID: steam: add battery device.
>
>  drivers/hid/Kconfig     |   8 +
>  drivers/hid/Makefile    |   1 +
>  drivers/hid/hid-ids.h   |   4 +
>  drivers/hid/hid-steam.c | 794 ++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 807 insertions(+)
>  create mode 100644 drivers/hid/hid-steam.c
>
> --
> 2.16.2
>

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox