cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

chromeos_laptop.c (22743B)


      1// SPDX-License-Identifier: GPL-2.0+
      2// Driver to instantiate Chromebook i2c/smbus devices.
      3//
      4// Copyright (C) 2012 Google, Inc.
      5// Author: Benson Leung <bleung@chromium.org>
      6
      7#define pr_fmt(fmt)		KBUILD_MODNAME ": " fmt
      8
      9#include <linux/acpi.h>
     10#include <linux/dmi.h>
     11#include <linux/i2c.h>
     12#include <linux/input.h>
     13#include <linux/interrupt.h>
     14#include <linux/ioport.h>
     15#include <linux/module.h>
     16#include <linux/pci.h>
     17#include <linux/platform_device.h>
     18#include <linux/property.h>
     19
     20#define ATMEL_TP_I2C_ADDR	0x4b
     21#define ATMEL_TP_I2C_BL_ADDR	0x25
     22#define ATMEL_TS_I2C_ADDR	0x4a
     23#define ATMEL_TS_I2C_BL_ADDR	0x26
     24#define CYAPA_TP_I2C_ADDR	0x67
     25#define ELAN_TP_I2C_ADDR	0x15
     26#define ISL_ALS_I2C_ADDR	0x44
     27#define TAOS_ALS_I2C_ADDR	0x29
     28
     29static const char *i2c_adapter_names[] = {
     30	"SMBus I801 adapter",
     31	"i915 gmbus vga",
     32	"i915 gmbus panel",
     33	"Synopsys DesignWare I2C adapter",
     34};
     35
     36/* Keep this enum consistent with i2c_adapter_names */
     37enum i2c_adapter_type {
     38	I2C_ADAPTER_SMBUS = 0,
     39	I2C_ADAPTER_VGADDC,
     40	I2C_ADAPTER_PANEL,
     41	I2C_ADAPTER_DESIGNWARE,
     42};
     43
     44struct i2c_peripheral {
     45	struct i2c_board_info board_info;
     46	unsigned short alt_addr;
     47
     48	const char *dmi_name;
     49	unsigned long irqflags;
     50	struct resource irq_resource;
     51
     52	enum i2c_adapter_type type;
     53	u32 pci_devid;
     54
     55	const struct property_entry *properties;
     56
     57	struct i2c_client *client;
     58};
     59
     60struct acpi_peripheral {
     61	char hid[ACPI_ID_LEN];
     62	struct software_node swnode;
     63	struct i2c_client *client;
     64};
     65
     66struct chromeos_laptop {
     67	/*
     68	 * Note that we can't mark this pointer as const because
     69	 * i2c_new_scanned_device() changes passed in I2C board info, so.
     70	 */
     71	struct i2c_peripheral *i2c_peripherals;
     72	unsigned int num_i2c_peripherals;
     73
     74	struct acpi_peripheral *acpi_peripherals;
     75	unsigned int num_acpi_peripherals;
     76};
     77
     78static const struct chromeos_laptop *cros_laptop;
     79
     80static struct i2c_client *
     81chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter,
     82				      struct i2c_board_info *info,
     83				      unsigned short alt_addr)
     84{
     85	const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END };
     86	struct i2c_client *client;
     87
     88	/*
     89	 * Add the i2c device. If we can't detect it at the primary
     90	 * address we scan secondary addresses. In any case the client
     91	 * structure gets assigned primary address.
     92	 */
     93	client = i2c_new_scanned_device(adapter, info, addr_list, NULL);
     94	if (IS_ERR(client) && alt_addr) {
     95		struct i2c_board_info dummy_info = {
     96			I2C_BOARD_INFO("dummy", info->addr),
     97		};
     98		const unsigned short alt_addr_list[] = {
     99			alt_addr, I2C_CLIENT_END
    100		};
    101		struct i2c_client *dummy;
    102
    103		dummy = i2c_new_scanned_device(adapter, &dummy_info,
    104					       alt_addr_list, NULL);
    105		if (!IS_ERR(dummy)) {
    106			pr_debug("%d-%02x is probed at %02x\n",
    107				 adapter->nr, info->addr, dummy->addr);
    108			i2c_unregister_device(dummy);
    109			client = i2c_new_client_device(adapter, info);
    110		}
    111	}
    112
    113	if (IS_ERR(client)) {
    114		client = NULL;
    115		pr_debug("failed to register device %d-%02x\n",
    116			 adapter->nr, info->addr);
    117	} else {
    118		pr_debug("added i2c device %d-%02x\n",
    119			 adapter->nr, info->addr);
    120	}
    121
    122	return client;
    123}
    124
    125static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid)
    126{
    127	struct pci_dev *pdev;
    128
    129	if (!dev_is_pci(dev))
    130		return false;
    131
    132	pdev = to_pci_dev(dev);
    133	return devid == pci_dev_id(pdev);
    134}
    135
    136static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
    137{
    138	struct i2c_peripheral *i2c_dev;
    139	int i;
    140
    141	for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
    142		i2c_dev = &cros_laptop->i2c_peripherals[i];
    143
    144		/* Skip devices already created */
    145		if (i2c_dev->client)
    146			continue;
    147
    148		if (strncmp(adapter->name, i2c_adapter_names[i2c_dev->type],
    149			    strlen(i2c_adapter_names[i2c_dev->type])))
    150			continue;
    151
    152		if (i2c_dev->pci_devid &&
    153		    !chromeos_laptop_match_adapter_devid(adapter->dev.parent,
    154							 i2c_dev->pci_devid)) {
    155			continue;
    156		}
    157
    158		i2c_dev->client =
    159			chromes_laptop_instantiate_i2c_device(adapter,
    160							&i2c_dev->board_info,
    161							i2c_dev->alt_addr);
    162	}
    163}
    164
    165static bool chromeos_laptop_adjust_client(struct i2c_client *client)
    166{
    167	struct acpi_peripheral *acpi_dev;
    168	struct acpi_device_id acpi_ids[2] = { };
    169	int i;
    170	int error;
    171
    172	if (!has_acpi_companion(&client->dev))
    173		return false;
    174
    175	for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
    176		acpi_dev = &cros_laptop->acpi_peripherals[i];
    177
    178		memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN);
    179
    180		if (acpi_match_device(acpi_ids, &client->dev)) {
    181			error = device_add_software_node(&client->dev, &acpi_dev->swnode);
    182			if (error) {
    183				dev_err(&client->dev,
    184					"failed to add properties: %d\n",
    185					error);
    186				break;
    187			}
    188
    189			acpi_dev->client = client;
    190
    191			return true;
    192		}
    193	}
    194
    195	return false;
    196}
    197
    198static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
    199{
    200	struct acpi_peripheral *acpi_dev;
    201	struct i2c_peripheral *i2c_dev;
    202	int i;
    203
    204	if (has_acpi_companion(&client->dev))
    205		for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
    206			acpi_dev = &cros_laptop->acpi_peripherals[i];
    207
    208			if (acpi_dev->client == client) {
    209				acpi_dev->client = NULL;
    210				return;
    211			}
    212		}
    213	else
    214		for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
    215			i2c_dev = &cros_laptop->i2c_peripherals[i];
    216
    217			if (i2c_dev->client == client) {
    218				i2c_dev->client = NULL;
    219				return;
    220			}
    221		}
    222}
    223
    224static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
    225					     unsigned long action, void *data)
    226{
    227	struct device *dev = data;
    228
    229	switch (action) {
    230	case BUS_NOTIFY_ADD_DEVICE:
    231		if (dev->type == &i2c_adapter_type)
    232			chromeos_laptop_check_adapter(to_i2c_adapter(dev));
    233		else if (dev->type == &i2c_client_type)
    234			chromeos_laptop_adjust_client(to_i2c_client(dev));
    235		break;
    236
    237	case BUS_NOTIFY_REMOVED_DEVICE:
    238		if (dev->type == &i2c_client_type)
    239			chromeos_laptop_detach_i2c_client(to_i2c_client(dev));
    240		break;
    241	}
    242
    243	return 0;
    244}
    245
    246static struct notifier_block chromeos_laptop_i2c_notifier = {
    247	.notifier_call = chromeos_laptop_i2c_notifier_call,
    248};
    249
    250#define DECLARE_CROS_LAPTOP(_name)					\
    251static const struct chromeos_laptop _name __initconst = {		\
    252	.i2c_peripherals	= _name##_peripherals,			\
    253	.num_i2c_peripherals	= ARRAY_SIZE(_name##_peripherals),	\
    254}
    255
    256#define DECLARE_ACPI_CROS_LAPTOP(_name)					\
    257static const struct chromeos_laptop _name __initconst = {		\
    258	.acpi_peripherals	= _name##_peripherals,			\
    259	.num_acpi_peripherals	= ARRAY_SIZE(_name##_peripherals),	\
    260}
    261
    262static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = {
    263	/* Touchpad. */
    264	{
    265		.board_info	= {
    266			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
    267			.flags		= I2C_CLIENT_WAKE,
    268		},
    269		.dmi_name	= "trackpad",
    270		.type		= I2C_ADAPTER_SMBUS,
    271	},
    272	/* Light Sensor. */
    273	{
    274		.board_info	= {
    275			I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
    276		},
    277		.dmi_name	= "lightsensor",
    278		.type		= I2C_ADAPTER_SMBUS,
    279	},
    280};
    281DECLARE_CROS_LAPTOP(samsung_series_5_550);
    282
    283static struct i2c_peripheral samsung_series_5_peripherals[] __initdata = {
    284	/* Light Sensor. */
    285	{
    286		.board_info	= {
    287			I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
    288		},
    289		.type		= I2C_ADAPTER_SMBUS,
    290	},
    291};
    292DECLARE_CROS_LAPTOP(samsung_series_5);
    293
    294static const int chromebook_pixel_tp_keys[] __initconst = {
    295	KEY_RESERVED,
    296	KEY_RESERVED,
    297	KEY_RESERVED,
    298	KEY_RESERVED,
    299	KEY_RESERVED,
    300	BTN_LEFT
    301};
    302
    303static const struct property_entry
    304chromebook_pixel_trackpad_props[] __initconst = {
    305	PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
    306	PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
    307	{ }
    308};
    309
    310static const struct property_entry
    311chromebook_atmel_touchscreen_props[] __initconst = {
    312	PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
    313	{ }
    314};
    315
    316static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
    317	/* Touch Screen. */
    318	{
    319		.board_info	= {
    320			I2C_BOARD_INFO("atmel_mxt_ts",
    321					ATMEL_TS_I2C_ADDR),
    322			.flags		= I2C_CLIENT_WAKE,
    323		},
    324		.dmi_name	= "touchscreen",
    325		.irqflags	= IRQF_TRIGGER_FALLING,
    326		.type		= I2C_ADAPTER_PANEL,
    327		.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
    328		.properties	= chromebook_atmel_touchscreen_props,
    329	},
    330	/* Touchpad. */
    331	{
    332		.board_info	= {
    333			I2C_BOARD_INFO("atmel_mxt_tp",
    334					ATMEL_TP_I2C_ADDR),
    335			.flags		= I2C_CLIENT_WAKE,
    336		},
    337		.dmi_name	= "trackpad",
    338		.irqflags	= IRQF_TRIGGER_FALLING,
    339		.type		= I2C_ADAPTER_VGADDC,
    340		.alt_addr	= ATMEL_TP_I2C_BL_ADDR,
    341		.properties	= chromebook_pixel_trackpad_props,
    342	},
    343	/* Light Sensor. */
    344	{
    345		.board_info	= {
    346			I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
    347		},
    348		.dmi_name	= "lightsensor",
    349		.type		= I2C_ADAPTER_PANEL,
    350	},
    351};
    352DECLARE_CROS_LAPTOP(chromebook_pixel);
    353
    354static struct i2c_peripheral hp_chromebook_14_peripherals[] __initdata = {
    355	/* Touchpad. */
    356	{
    357		.board_info	= {
    358			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
    359			.flags		= I2C_CLIENT_WAKE,
    360		},
    361		.dmi_name	= "trackpad",
    362		.type		= I2C_ADAPTER_DESIGNWARE,
    363	},
    364};
    365DECLARE_CROS_LAPTOP(hp_chromebook_14);
    366
    367static struct i2c_peripheral dell_chromebook_11_peripherals[] __initdata = {
    368	/* Touchpad. */
    369	{
    370		.board_info	= {
    371			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
    372			.flags		= I2C_CLIENT_WAKE,
    373		},
    374		.dmi_name	= "trackpad",
    375		.type		= I2C_ADAPTER_DESIGNWARE,
    376	},
    377	/* Elan Touchpad option. */
    378	{
    379		.board_info	= {
    380			I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
    381			.flags		= I2C_CLIENT_WAKE,
    382		},
    383		.dmi_name	= "trackpad",
    384		.type		= I2C_ADAPTER_DESIGNWARE,
    385	},
    386};
    387DECLARE_CROS_LAPTOP(dell_chromebook_11);
    388
    389static struct i2c_peripheral toshiba_cb35_peripherals[] __initdata = {
    390	/* Touchpad. */
    391	{
    392		.board_info	= {
    393			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
    394			.flags		= I2C_CLIENT_WAKE,
    395		},
    396		.dmi_name	= "trackpad",
    397		.type		= I2C_ADAPTER_DESIGNWARE,
    398	},
    399};
    400DECLARE_CROS_LAPTOP(toshiba_cb35);
    401
    402static struct i2c_peripheral acer_c7_chromebook_peripherals[] __initdata = {
    403	/* Touchpad. */
    404	{
    405		.board_info	= {
    406			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
    407			.flags		= I2C_CLIENT_WAKE,
    408		},
    409		.dmi_name	= "trackpad",
    410		.type		= I2C_ADAPTER_SMBUS,
    411	},
    412};
    413DECLARE_CROS_LAPTOP(acer_c7_chromebook);
    414
    415static struct i2c_peripheral acer_ac700_peripherals[] __initdata = {
    416	/* Light Sensor. */
    417	{
    418		.board_info	= {
    419			I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
    420		},
    421		.type		= I2C_ADAPTER_SMBUS,
    422	},
    423};
    424DECLARE_CROS_LAPTOP(acer_ac700);
    425
    426static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
    427	/* Touchscreen. */
    428	{
    429		.board_info	= {
    430			I2C_BOARD_INFO("atmel_mxt_ts",
    431					ATMEL_TS_I2C_ADDR),
    432			.flags		= I2C_CLIENT_WAKE,
    433		},
    434		.dmi_name	= "touchscreen",
    435		.irqflags	= IRQF_TRIGGER_FALLING,
    436		.type		= I2C_ADAPTER_DESIGNWARE,
    437		.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
    438		.alt_addr	= ATMEL_TS_I2C_BL_ADDR,
    439		.properties	= chromebook_atmel_touchscreen_props,
    440	},
    441	/* Touchpad. */
    442	{
    443		.board_info	= {
    444			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
    445			.flags		= I2C_CLIENT_WAKE,
    446		},
    447		.dmi_name	= "trackpad",
    448		.type		= I2C_ADAPTER_DESIGNWARE,
    449		.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
    450	},
    451	/* Elan Touchpad option. */
    452	{
    453		.board_info	= {
    454			I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR),
    455			.flags		= I2C_CLIENT_WAKE,
    456		},
    457		.dmi_name	= "trackpad",
    458		.type		= I2C_ADAPTER_DESIGNWARE,
    459		.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)),
    460	},
    461	/* Light Sensor. */
    462	{
    463		.board_info	= {
    464			I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
    465		},
    466		.dmi_name	= "lightsensor",
    467		.type		= I2C_ADAPTER_DESIGNWARE,
    468		.pci_devid	= PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)),
    469	},
    470};
    471DECLARE_CROS_LAPTOP(acer_c720);
    472
    473static struct i2c_peripheral
    474hp_pavilion_14_chromebook_peripherals[] __initdata = {
    475	/* Touchpad. */
    476	{
    477		.board_info	= {
    478			I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR),
    479			.flags		= I2C_CLIENT_WAKE,
    480		},
    481		.dmi_name	= "trackpad",
    482		.type		= I2C_ADAPTER_SMBUS,
    483	},
    484};
    485DECLARE_CROS_LAPTOP(hp_pavilion_14_chromebook);
    486
    487static struct i2c_peripheral cr48_peripherals[] __initdata = {
    488	/* Light Sensor. */
    489	{
    490		.board_info	= {
    491			I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
    492		},
    493		.type		= I2C_ADAPTER_SMBUS,
    494	},
    495};
    496DECLARE_CROS_LAPTOP(cr48);
    497
    498static const u32 samus_touchpad_buttons[] __initconst = {
    499	KEY_RESERVED,
    500	KEY_RESERVED,
    501	KEY_RESERVED,
    502	BTN_LEFT
    503};
    504
    505static const struct property_entry samus_trackpad_props[] __initconst = {
    506	PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
    507	PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons),
    508	{ }
    509};
    510
    511static struct acpi_peripheral samus_peripherals[] __initdata = {
    512	/* Touchpad */
    513	{
    514		.hid		= "ATML0000",
    515		.swnode		= {
    516			.properties = samus_trackpad_props,
    517		},
    518	},
    519	/* Touchsceen */
    520	{
    521		.hid		= "ATML0001",
    522		.swnode		= {
    523			.properties = chromebook_atmel_touchscreen_props,
    524		},
    525	},
    526};
    527DECLARE_ACPI_CROS_LAPTOP(samus);
    528
    529static struct acpi_peripheral generic_atmel_peripherals[] __initdata = {
    530	/* Touchpad */
    531	{
    532		.hid		= "ATML0000",
    533		.swnode		= {
    534			.properties = chromebook_pixel_trackpad_props,
    535		},
    536	},
    537	/* Touchsceen */
    538	{
    539		.hid		= "ATML0001",
    540		.swnode		= {
    541			.properties = chromebook_atmel_touchscreen_props,
    542		},
    543	},
    544};
    545DECLARE_ACPI_CROS_LAPTOP(generic_atmel);
    546
    547static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
    548	{
    549		.ident = "Samsung Series 5 550",
    550		.matches = {
    551			DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
    552			DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
    553		},
    554		.driver_data = (void *)&samsung_series_5_550,
    555	},
    556	{
    557		.ident = "Samsung Series 5",
    558		.matches = {
    559			DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
    560		},
    561		.driver_data = (void *)&samsung_series_5,
    562	},
    563	{
    564		.ident = "Chromebook Pixel",
    565		.matches = {
    566			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
    567			DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
    568		},
    569		.driver_data = (void *)&chromebook_pixel,
    570	},
    571	{
    572		.ident = "Wolf",
    573		.matches = {
    574			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
    575			DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"),
    576		},
    577		.driver_data = (void *)&dell_chromebook_11,
    578	},
    579	{
    580		.ident = "HP Chromebook 14",
    581		.matches = {
    582			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
    583			DMI_MATCH(DMI_PRODUCT_NAME, "Falco"),
    584		},
    585		.driver_data = (void *)&hp_chromebook_14,
    586	},
    587	{
    588		.ident = "Toshiba CB35",
    589		.matches = {
    590			DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
    591			DMI_MATCH(DMI_PRODUCT_NAME, "Leon"),
    592		},
    593		.driver_data = (void *)&toshiba_cb35,
    594	},
    595	{
    596		.ident = "Acer C7 Chromebook",
    597		.matches = {
    598			DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
    599		},
    600		.driver_data = (void *)&acer_c7_chromebook,
    601	},
    602	{
    603		.ident = "Acer AC700",
    604		.matches = {
    605			DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
    606		},
    607		.driver_data = (void *)&acer_ac700,
    608	},
    609	{
    610		.ident = "Acer C720",
    611		.matches = {
    612			DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"),
    613		},
    614		.driver_data = (void *)&acer_c720,
    615	},
    616	{
    617		.ident = "HP Pavilion 14 Chromebook",
    618		.matches = {
    619			DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
    620		},
    621		.driver_data = (void *)&hp_pavilion_14_chromebook,
    622	},
    623	{
    624		.ident = "Cr-48",
    625		.matches = {
    626			DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
    627		},
    628		.driver_data = (void *)&cr48,
    629	},
    630	/* Devices with peripherals incompletely described in ACPI */
    631	{
    632		.ident = "Chromebook Pro",
    633		.matches = {
    634			DMI_MATCH(DMI_SYS_VENDOR, "Google"),
    635			DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"),
    636		},
    637		.driver_data = (void *)&samus,
    638	},
    639	{
    640		.ident = "Google Pixel 2 (2015)",
    641		.matches = {
    642			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
    643			DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
    644		},
    645		.driver_data = (void *)&samus,
    646	},
    647	{
    648		.ident = "Samsung Chromebook 3",
    649		.matches = {
    650			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
    651			DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
    652		},
    653		.driver_data = (void *)&samus,
    654	},
    655	{
    656		/*
    657		 * Other Chromebooks with Atmel touch controllers:
    658		 * - Winky (touchpad)
    659		 * - Clapper, Expresso, Rambi, Glimmer (touchscreen)
    660		 */
    661		.ident = "Other Chromebook",
    662		.matches = {
    663			/*
    664			 * This will match all Google devices, not only devices
    665			 * with Atmel, but we will validate that the device
    666			 * actually has matching peripherals.
    667			 */
    668			DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
    669		},
    670		.driver_data = (void *)&generic_atmel,
    671	},
    672	{ }
    673};
    674MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
    675
    676static int __init chromeos_laptop_scan_peripherals(struct device *dev, void *data)
    677{
    678	int error;
    679
    680	if (dev->type == &i2c_adapter_type) {
    681		chromeos_laptop_check_adapter(to_i2c_adapter(dev));
    682	} else if (dev->type == &i2c_client_type) {
    683		if (chromeos_laptop_adjust_client(to_i2c_client(dev))) {
    684			/*
    685			 * Now that we have needed properties re-trigger
    686			 * driver probe in case driver was initialized
    687			 * earlier and probe failed.
    688			 */
    689			error = device_attach(dev);
    690			if (error < 0)
    691				dev_warn(dev,
    692					 "%s: device_attach() failed: %d\n",
    693					 __func__, error);
    694		}
    695	}
    696
    697	return 0;
    698}
    699
    700static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name)
    701{
    702	const struct dmi_device *dmi_dev;
    703	const struct dmi_dev_onboard *dev_data;
    704
    705	dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL);
    706	if (!dmi_dev) {
    707		pr_err("failed to find DMI device '%s'\n", dmi_name);
    708		return -ENOENT;
    709	}
    710
    711	dev_data = dmi_dev->device_data;
    712	if (!dev_data) {
    713		pr_err("failed to get data from DMI for '%s'\n", dmi_name);
    714		return -EINVAL;
    715	}
    716
    717	return dev_data->instance;
    718}
    719
    720static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev)
    721{
    722	int irq;
    723
    724	if (i2c_dev->dmi_name) {
    725		irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name);
    726		if (irq < 0)
    727			return irq;
    728
    729		i2c_dev->irq_resource  = (struct resource)
    730			DEFINE_RES_NAMED(irq, 1, NULL,
    731					 IORESOURCE_IRQ | i2c_dev->irqflags);
    732		i2c_dev->board_info.resources = &i2c_dev->irq_resource;
    733		i2c_dev->board_info.num_resources = 1;
    734	}
    735
    736	return 0;
    737}
    738
    739static int __init
    740chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop,
    741					const struct chromeos_laptop *src)
    742{
    743	struct i2c_peripheral *i2c_dev;
    744	struct i2c_board_info *info;
    745	int i;
    746	int error;
    747
    748	if (!src->num_i2c_peripherals)
    749		return 0;
    750
    751	cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals,
    752					       src->num_i2c_peripherals *
    753						sizeof(*src->i2c_peripherals),
    754					       GFP_KERNEL);
    755	if (!cros_laptop->i2c_peripherals)
    756		return -ENOMEM;
    757
    758	cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals;
    759
    760	for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
    761		i2c_dev = &cros_laptop->i2c_peripherals[i];
    762		info = &i2c_dev->board_info;
    763
    764		error = chromeos_laptop_setup_irq(i2c_dev);
    765		if (error)
    766			goto err_out;
    767
    768		/* Create primary fwnode for the device - copies everything */
    769		if (i2c_dev->properties) {
    770			info->fwnode = fwnode_create_software_node(i2c_dev->properties, NULL);
    771			if (IS_ERR(info->fwnode)) {
    772				error = PTR_ERR(info->fwnode);
    773				goto err_out;
    774			}
    775		}
    776	}
    777
    778	return 0;
    779
    780err_out:
    781	while (--i >= 0) {
    782		i2c_dev = &cros_laptop->i2c_peripherals[i];
    783		info = &i2c_dev->board_info;
    784		if (!IS_ERR_OR_NULL(info->fwnode))
    785			fwnode_remove_software_node(info->fwnode);
    786	}
    787	kfree(cros_laptop->i2c_peripherals);
    788	return error;
    789}
    790
    791static int __init
    792chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop,
    793					const struct chromeos_laptop *src)
    794{
    795	struct acpi_peripheral *acpi_peripherals;
    796	struct acpi_peripheral *acpi_dev;
    797	const struct acpi_peripheral *src_dev;
    798	int n_peripherals = 0;
    799	int i;
    800	int error;
    801
    802	for (i = 0; i < src->num_acpi_peripherals; i++) {
    803		if (acpi_dev_present(src->acpi_peripherals[i].hid, NULL, -1))
    804			n_peripherals++;
    805	}
    806
    807	if (!n_peripherals)
    808		return 0;
    809
    810	acpi_peripherals = kcalloc(n_peripherals,
    811				   sizeof(*src->acpi_peripherals),
    812				   GFP_KERNEL);
    813	if (!acpi_peripherals)
    814		return -ENOMEM;
    815
    816	acpi_dev = acpi_peripherals;
    817	for (i = 0; i < src->num_acpi_peripherals; i++) {
    818		src_dev = &src->acpi_peripherals[i];
    819		if (!acpi_dev_present(src_dev->hid, NULL, -1))
    820			continue;
    821
    822		*acpi_dev = *src_dev;
    823
    824		/* We need to deep-copy properties */
    825		if (src_dev->swnode.properties) {
    826			acpi_dev->swnode.properties =
    827				property_entries_dup(src_dev->swnode.properties);
    828			if (IS_ERR(acpi_dev->swnode.properties)) {
    829				error = PTR_ERR(acpi_dev->swnode.properties);
    830				goto err_out;
    831			}
    832		}
    833
    834		acpi_dev++;
    835	}
    836
    837	cros_laptop->acpi_peripherals = acpi_peripherals;
    838	cros_laptop->num_acpi_peripherals = n_peripherals;
    839
    840	return 0;
    841
    842err_out:
    843	while (--i >= 0) {
    844		acpi_dev = &acpi_peripherals[i];
    845		if (!IS_ERR_OR_NULL(acpi_dev->swnode.properties))
    846			property_entries_free(acpi_dev->swnode.properties);
    847	}
    848
    849	kfree(acpi_peripherals);
    850	return error;
    851}
    852
    853static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
    854{
    855	const struct acpi_peripheral *acpi_dev;
    856	struct i2c_peripheral *i2c_dev;
    857	int i;
    858
    859	for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) {
    860		i2c_dev = &cros_laptop->i2c_peripherals[i];
    861		i2c_unregister_device(i2c_dev->client);
    862	}
    863
    864	for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
    865		acpi_dev = &cros_laptop->acpi_peripherals[i];
    866
    867		if (acpi_dev->client)
    868			device_remove_software_node(&acpi_dev->client->dev);
    869
    870		property_entries_free(acpi_dev->swnode.properties);
    871	}
    872
    873	kfree(cros_laptop->i2c_peripherals);
    874	kfree(cros_laptop->acpi_peripherals);
    875	kfree(cros_laptop);
    876}
    877
    878static struct chromeos_laptop * __init
    879chromeos_laptop_prepare(const struct chromeos_laptop *src)
    880{
    881	struct chromeos_laptop *cros_laptop;
    882	int error;
    883
    884	cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
    885	if (!cros_laptop)
    886		return ERR_PTR(-ENOMEM);
    887
    888	error = chromeos_laptop_prepare_i2c_peripherals(cros_laptop, src);
    889	if (!error)
    890		error = chromeos_laptop_prepare_acpi_peripherals(cros_laptop,
    891								 src);
    892
    893	if (error) {
    894		chromeos_laptop_destroy(cros_laptop);
    895		return ERR_PTR(error);
    896	}
    897
    898	return cros_laptop;
    899}
    900
    901static int __init chromeos_laptop_init(void)
    902{
    903	const struct dmi_system_id *dmi_id;
    904	int error;
    905
    906	dmi_id = dmi_first_match(chromeos_laptop_dmi_table);
    907	if (!dmi_id) {
    908		pr_debug("unsupported system\n");
    909		return -ENODEV;
    910	}
    911
    912	pr_debug("DMI Matched %s\n", dmi_id->ident);
    913
    914	cros_laptop = chromeos_laptop_prepare((void *)dmi_id->driver_data);
    915	if (IS_ERR(cros_laptop))
    916		return PTR_ERR(cros_laptop);
    917
    918	if (!cros_laptop->num_i2c_peripherals &&
    919	    !cros_laptop->num_acpi_peripherals) {
    920		pr_debug("no relevant devices detected\n");
    921		error = -ENODEV;
    922		goto err_destroy_cros_laptop;
    923	}
    924
    925	error = bus_register_notifier(&i2c_bus_type,
    926				      &chromeos_laptop_i2c_notifier);
    927	if (error) {
    928		pr_err("failed to register i2c bus notifier: %d\n",
    929		       error);
    930		goto err_destroy_cros_laptop;
    931	}
    932
    933	/*
    934	 * Scan adapters that have been registered and clients that have
    935	 * been created before we installed the notifier to make sure
    936	 * we do not miss any devices.
    937	 */
    938	i2c_for_each_dev(NULL, chromeos_laptop_scan_peripherals);
    939
    940	return 0;
    941
    942err_destroy_cros_laptop:
    943	chromeos_laptop_destroy(cros_laptop);
    944	return error;
    945}
    946
    947static void __exit chromeos_laptop_exit(void)
    948{
    949	bus_unregister_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier);
    950	chromeos_laptop_destroy(cros_laptop);
    951}
    952
    953module_init(chromeos_laptop_init);
    954module_exit(chromeos_laptop_exit);
    955
    956MODULE_DESCRIPTION("Chrome OS Laptop driver");
    957MODULE_AUTHOR("Benson Leung <bleung@chromium.org>");
    958MODULE_LICENSE("GPL");