mirror of
https://github.com/torvalds/linux.git
synced 2024-11-11 22:51:42 +00:00
Changes to chrome-platform for v4.18
Further changes from Dmitry related to the removal of platform data from atmel_mxt_ts and chromeos_laptop. This time, we have some changes that teach chromeos_laptop how to supply acpi properties for some input devices so that the peripheral driver doesn't have to do dmi matching on some Chromebook platforms. Also adds the Chromebook Tablet switch driver, which is useful for x86 convertible Chromebooks. Other misc. cleanup. Thanks, Benson -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEE6gYDF28Li+nEiKLaHwn1ewov5lgFAlsUrmMACgkQHwn1ewov 5ljpzRAAqgscZzPqHZNOtLC/QXsohdCKnbfjVL1Nd+xor773kJwA0jJVU6fSfvzx sxqQkRUno3aFD3TeKzRVY+jBXzb8hkYUpIfvT2Fl3fGK26NIFaB+F0wqqwZZcyOt 36lR7Ngtun3HvrxxiJ8utQeF4z5fofpWRwSGzE+ADalBr47NSIBM2JofcWmo35tk pw0wkZvvJhzSlouF4JW8ca6LjPpk6Ngw2988HEDzyXlYGwdS/IXGjriMQ5AIiRuE qAFtydRYYcBfZ9IH7O3Utmq74mDg+UXcFjnnt8lrvbca8QiPRWvblxwkQ5alpbPQ x/HS9dJqkPfy5xskKiivDSKCtYXSNi5E15crcbhreiZwSlX2ictVIYu9zEo2KYCh aD0Ba1iCQVCs8uXdoIqIh92LDLzgkr8L7kjqqFwDWpQeEH5LGYtOaHD17e5vIBc8 dllkAiJfRPVtcJtdZgUkW7NwKl8CdKFAMi2X5owYCyEsPgwUtpi2xfO6xSpA2gWl +srbY22RTcwmMgds0kktS46GgbW73rdFxEIlbeR6moaO6GUEILicsxu6BzvXYxuj pfsjAt1CP50Hy1kInyiFjtgEwIEv0vbr39DsZNTWWjMFXlZHzmOc8JbjFK1lb+Kw Hh2x31BtXHA4pFyk2DUem9ctqybDZePt1vlN5QYz7WjHzMeJRqg= =mA72 -----END PGP SIGNATURE----- Merge tag 'chrome-platform-for-linus-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform Pull chrome platform updates from Benson Leung: - further changes from Dmitry related to the removal of platform data from atmel_mxt_ts and chromeos_laptop. This time, we have some changes that teach chromeos_laptop how to supply acpi properties for some input devices so that the peripheral driver doesn't have to do dmi matching on some Chromebook platforms. - new Chromebook Tablet switch driver, which is useful for x86 convertible Chromebooks. - other misc cleanup * tag 'chrome-platform-for-linus-4.18' of git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform: platform/chrome: Use to_cros_ec_dev more broadly platform/chrome: chromeos_laptop: fix touchpad button mapping on Celes platform: chrome: Add input dependency for tablet switch driver platform/chrome: chromeos_laptop - supply properties for ACPI devices platform/chrome: chromeos_tbmc - add SPDX identifier platform: chrome: Add Tablet Switch ACPI driver platform/chrome: cros_ec_lpc: do not try DMI match when ACPI device found
This commit is contained in:
commit
910470e03f
@ -38,6 +38,17 @@ config CHROMEOS_PSTORE
|
||||
If you have a supported Chromebook, choose Y or M here.
|
||||
The module will be called chromeos_pstore.
|
||||
|
||||
config CHROMEOS_TBMC
|
||||
tristate "ChromeOS Tablet Switch Controller"
|
||||
depends on ACPI
|
||||
depends on INPUT
|
||||
help
|
||||
This option adds a driver for the tablet switch on
|
||||
select Chrome OS systems.
|
||||
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called chromeos_tbmc.
|
||||
|
||||
config CROS_EC_CTL
|
||||
tristate
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
|
||||
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
|
||||
obj-$(CONFIG_CHROMEOS_TBMC) += chromeos_tbmc.o
|
||||
cros_ec_ctl-objs := cros_ec_sysfs.o cros_ec_lightbar.o \
|
||||
cros_ec_vbc.o cros_ec_debugfs.o
|
||||
obj-$(CONFIG_CROS_EC_CTL) += cros_ec_ctl.o
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/input.h>
|
||||
@ -54,6 +55,11 @@ struct i2c_peripheral {
|
||||
struct i2c_client *client;
|
||||
};
|
||||
|
||||
struct acpi_peripheral {
|
||||
char hid[ACPI_ID_LEN];
|
||||
const struct property_entry *properties;
|
||||
};
|
||||
|
||||
struct chromeos_laptop {
|
||||
/*
|
||||
* Note that we can't mark this pointer as const because
|
||||
@ -61,6 +67,9 @@ struct chromeos_laptop {
|
||||
*/
|
||||
struct i2c_peripheral *i2c_peripherals;
|
||||
unsigned int num_i2c_peripherals;
|
||||
|
||||
const struct acpi_peripheral *acpi_peripherals;
|
||||
unsigned int num_acpi_peripherals;
|
||||
};
|
||||
|
||||
static const struct chromeos_laptop *cros_laptop;
|
||||
@ -148,6 +157,38 @@ static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
|
||||
}
|
||||
}
|
||||
|
||||
static bool chromeos_laptop_adjust_client(struct i2c_client *client)
|
||||
{
|
||||
const struct acpi_peripheral *acpi_dev;
|
||||
struct acpi_device_id acpi_ids[2] = { };
|
||||
int i;
|
||||
int error;
|
||||
|
||||
if (!has_acpi_companion(&client->dev))
|
||||
return false;
|
||||
|
||||
for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
|
||||
acpi_dev = &cros_laptop->acpi_peripherals[i];
|
||||
|
||||
memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN);
|
||||
|
||||
if (acpi_match_device(acpi_ids, &client->dev)) {
|
||||
error = device_add_properties(&client->dev,
|
||||
acpi_dev->properties);
|
||||
if (error) {
|
||||
dev_err(&client->dev,
|
||||
"failed to add properties: %d\n",
|
||||
error);
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
|
||||
{
|
||||
struct i2c_peripheral *i2c_dev;
|
||||
@ -170,6 +211,8 @@ static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
|
||||
case BUS_NOTIFY_ADD_DEVICE:
|
||||
if (dev->type == &i2c_adapter_type)
|
||||
chromeos_laptop_check_adapter(to_i2c_adapter(dev));
|
||||
else if (dev->type == &i2c_client_type)
|
||||
chromeos_laptop_adjust_client(to_i2c_client(dev));
|
||||
break;
|
||||
|
||||
case BUS_NOTIFY_REMOVED_DEVICE:
|
||||
@ -191,6 +234,12 @@ static const struct chromeos_laptop _name __initconst = { \
|
||||
.num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \
|
||||
}
|
||||
|
||||
#define DECLARE_ACPI_CROS_LAPTOP(_name) \
|
||||
static const struct chromeos_laptop _name __initconst = { \
|
||||
.acpi_peripherals = _name##_peripherals, \
|
||||
.num_acpi_peripherals = ARRAY_SIZE(_name##_peripherals), \
|
||||
}
|
||||
|
||||
static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = {
|
||||
/* Touchpad. */
|
||||
{
|
||||
@ -234,16 +283,25 @@ static const int chromebook_pixel_tp_keys[] __initconst = {
|
||||
|
||||
static const struct property_entry
|
||||
chromebook_pixel_trackpad_props[] __initconst = {
|
||||
PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
|
||||
PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
|
||||
{ }
|
||||
};
|
||||
|
||||
static const struct property_entry
|
||||
chromebook_atmel_touchscreen_props[] __initconst = {
|
||||
PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
|
||||
/* Touch Screen. */
|
||||
{
|
||||
.board_info = {
|
||||
I2C_BOARD_INFO("atmel_mxt_ts",
|
||||
ATMEL_TS_I2C_ADDR),
|
||||
.properties =
|
||||
chromebook_atmel_touchscreen_props,
|
||||
.flags = I2C_CLIENT_WAKE,
|
||||
},
|
||||
.dmi_name = "touchscreen",
|
||||
@ -354,6 +412,8 @@ static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
|
||||
.board_info = {
|
||||
I2C_BOARD_INFO("atmel_mxt_ts",
|
||||
ATMEL_TS_I2C_ADDR),
|
||||
.properties =
|
||||
chromebook_atmel_touchscreen_props,
|
||||
.flags = I2C_CLIENT_WAKE,
|
||||
},
|
||||
.dmi_name = "touchscreen",
|
||||
@ -419,6 +479,47 @@ static struct i2c_peripheral cr48_peripherals[] __initdata = {
|
||||
};
|
||||
DECLARE_CROS_LAPTOP(cr48);
|
||||
|
||||
static const u32 samus_touchpad_buttons[] __initconst = {
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
KEY_RESERVED,
|
||||
BTN_LEFT
|
||||
};
|
||||
|
||||
static const struct property_entry samus_trackpad_props[] __initconst = {
|
||||
PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
|
||||
PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons),
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct acpi_peripheral samus_peripherals[] __initdata = {
|
||||
/* Touchpad */
|
||||
{
|
||||
.hid = "ATML0000",
|
||||
.properties = samus_trackpad_props,
|
||||
},
|
||||
/* Touchsceen */
|
||||
{
|
||||
.hid = "ATML0001",
|
||||
.properties = chromebook_atmel_touchscreen_props,
|
||||
},
|
||||
};
|
||||
DECLARE_ACPI_CROS_LAPTOP(samus);
|
||||
|
||||
static struct acpi_peripheral generic_atmel_peripherals[] __initdata = {
|
||||
/* Touchpad */
|
||||
{
|
||||
.hid = "ATML0000",
|
||||
.properties = chromebook_pixel_trackpad_props,
|
||||
},
|
||||
/* Touchsceen */
|
||||
{
|
||||
.hid = "ATML0001",
|
||||
.properties = chromebook_atmel_touchscreen_props,
|
||||
},
|
||||
};
|
||||
DECLARE_ACPI_CROS_LAPTOP(generic_atmel);
|
||||
|
||||
static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
|
||||
{
|
||||
.ident = "Samsung Series 5 550",
|
||||
@ -502,17 +603,72 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
|
||||
},
|
||||
.driver_data = (void *)&cr48,
|
||||
},
|
||||
/* Devices with peripherals incompletely described in ACPI */
|
||||
{
|
||||
.ident = "Chromebook Pro",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "Google"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"),
|
||||
},
|
||||
.driver_data = (void *)&samus,
|
||||
},
|
||||
{
|
||||
.ident = "Google Pixel 2 (2015)",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
|
||||
},
|
||||
.driver_data = (void *)&samus,
|
||||
},
|
||||
{
|
||||
.ident = "Samsung Chromebook 3",
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Celes"),
|
||||
},
|
||||
.driver_data = (void *)&samus,
|
||||
},
|
||||
{
|
||||
/*
|
||||
* Other Chromebooks with Atmel touch controllers:
|
||||
* - Winky (touchpad)
|
||||
* - Clapper, Expresso, Rambi, Glimmer (touchscreen)
|
||||
*/
|
||||
.ident = "Other Chromebook",
|
||||
.matches = {
|
||||
/*
|
||||
* This will match all Google devices, not only devices
|
||||
* with Atmel, but we will validate that the device
|
||||
* actually has matching peripherals.
|
||||
*/
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
|
||||
},
|
||||
.driver_data = (void *)&generic_atmel,
|
||||
},
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
|
||||
|
||||
static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data)
|
||||
static int __init chromeos_laptop_scan_peripherals(struct device *dev, void *data)
|
||||
{
|
||||
struct i2c_adapter *adapter;
|
||||
int error;
|
||||
|
||||
adapter = i2c_verify_adapter(dev);
|
||||
if (adapter)
|
||||
chromeos_laptop_check_adapter(adapter);
|
||||
if (dev->type == &i2c_adapter_type) {
|
||||
chromeos_laptop_check_adapter(to_i2c_adapter(dev));
|
||||
} else if (dev->type == &i2c_client_type) {
|
||||
if (chromeos_laptop_adjust_client(to_i2c_client(dev))) {
|
||||
/*
|
||||
* Now that we have needed properties re-trigger
|
||||
* driver probe in case driver was initialized
|
||||
* earlier and probe failed.
|
||||
*/
|
||||
error = device_attach(dev);
|
||||
if (error < 0)
|
||||
dev_warn(dev,
|
||||
"%s: device_attach() failed: %d\n",
|
||||
__func__, error);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -556,27 +712,24 @@ static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct chromeos_laptop * __init
|
||||
chromeos_laptop_prepare(const struct chromeos_laptop *src)
|
||||
static int __init
|
||||
chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop,
|
||||
const struct chromeos_laptop *src)
|
||||
{
|
||||
struct chromeos_laptop *cros_laptop;
|
||||
struct i2c_peripheral *i2c_dev;
|
||||
struct i2c_board_info *info;
|
||||
int error;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
|
||||
if (!cros_laptop)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (!src->num_i2c_peripherals)
|
||||
return 0;
|
||||
|
||||
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;
|
||||
}
|
||||
if (!cros_laptop->i2c_peripherals)
|
||||
return -ENOMEM;
|
||||
|
||||
cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals;
|
||||
|
||||
@ -586,7 +739,7 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src)
|
||||
|
||||
error = chromeos_laptop_setup_irq(i2c_dev);
|
||||
if (error)
|
||||
goto err_destroy_cros_peripherals;
|
||||
goto err_out;
|
||||
|
||||
/* We need to deep-copy properties */
|
||||
if (info->properties) {
|
||||
@ -594,14 +747,14 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src)
|
||||
property_entries_dup(info->properties);
|
||||
if (IS_ERR(info->properties)) {
|
||||
error = PTR_ERR(info->properties);
|
||||
goto err_destroy_cros_peripherals;
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cros_laptop;
|
||||
return 0;
|
||||
|
||||
err_destroy_cros_peripherals:
|
||||
err_out:
|
||||
while (--i >= 0) {
|
||||
i2c_dev = &cros_laptop->i2c_peripherals[i];
|
||||
info = &i2c_dev->board_info;
|
||||
@ -609,13 +762,74 @@ err_destroy_cros_peripherals:
|
||||
property_entries_free(info->properties);
|
||||
}
|
||||
kfree(cros_laptop->i2c_peripherals);
|
||||
err_free_cros_laptop:
|
||||
kfree(cros_laptop);
|
||||
return ERR_PTR(error);
|
||||
return error;
|
||||
}
|
||||
|
||||
static int __init
|
||||
chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop,
|
||||
const struct chromeos_laptop *src)
|
||||
{
|
||||
struct acpi_peripheral *acpi_peripherals;
|
||||
struct acpi_peripheral *acpi_dev;
|
||||
const struct acpi_peripheral *src_dev;
|
||||
int n_peripherals = 0;
|
||||
int i;
|
||||
int error;
|
||||
|
||||
for (i = 0; i < src->num_acpi_peripherals; i++) {
|
||||
if (acpi_dev_present(src->acpi_peripherals[i].hid, NULL, -1))
|
||||
n_peripherals++;
|
||||
}
|
||||
|
||||
if (!n_peripherals)
|
||||
return 0;
|
||||
|
||||
acpi_peripherals = kcalloc(n_peripherals,
|
||||
sizeof(*src->acpi_peripherals),
|
||||
GFP_KERNEL);
|
||||
if (!acpi_peripherals)
|
||||
return -ENOMEM;
|
||||
|
||||
acpi_dev = acpi_peripherals;
|
||||
for (i = 0; i < src->num_acpi_peripherals; i++) {
|
||||
src_dev = &src->acpi_peripherals[i];
|
||||
if (!acpi_dev_present(src_dev->hid, NULL, -1))
|
||||
continue;
|
||||
|
||||
*acpi_dev = *src_dev;
|
||||
|
||||
/* We need to deep-copy properties */
|
||||
if (src_dev->properties) {
|
||||
acpi_dev->properties =
|
||||
property_entries_dup(src_dev->properties);
|
||||
if (IS_ERR(acpi_dev->properties)) {
|
||||
error = PTR_ERR(acpi_dev->properties);
|
||||
goto err_out;
|
||||
}
|
||||
}
|
||||
|
||||
acpi_dev++;
|
||||
}
|
||||
|
||||
cros_laptop->acpi_peripherals = acpi_peripherals;
|
||||
cros_laptop->num_acpi_peripherals = n_peripherals;
|
||||
|
||||
return 0;
|
||||
|
||||
err_out:
|
||||
while (--i >= 0) {
|
||||
acpi_dev = &acpi_peripherals[i];
|
||||
if (acpi_dev->properties)
|
||||
property_entries_free(acpi_dev->properties);
|
||||
}
|
||||
|
||||
kfree(acpi_peripherals);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
|
||||
{
|
||||
const struct acpi_peripheral *acpi_dev;
|
||||
struct i2c_peripheral *i2c_dev;
|
||||
struct i2c_board_info *info;
|
||||
int i;
|
||||
@ -631,10 +845,41 @@ static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
|
||||
property_entries_free(info->properties);
|
||||
}
|
||||
|
||||
for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
|
||||
acpi_dev = &cros_laptop->acpi_peripherals[i];
|
||||
|
||||
if (acpi_dev->properties)
|
||||
property_entries_free(acpi_dev->properties);
|
||||
}
|
||||
|
||||
kfree(cros_laptop->i2c_peripherals);
|
||||
kfree(cros_laptop->acpi_peripherals);
|
||||
kfree(cros_laptop);
|
||||
}
|
||||
|
||||
static struct chromeos_laptop * __init
|
||||
chromeos_laptop_prepare(const struct chromeos_laptop *src)
|
||||
{
|
||||
struct chromeos_laptop *cros_laptop;
|
||||
int error;
|
||||
|
||||
cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
|
||||
if (!cros_laptop)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
error = chromeos_laptop_prepare_i2c_peripherals(cros_laptop, src);
|
||||
if (!error)
|
||||
error = chromeos_laptop_prepare_acpi_peripherals(cros_laptop,
|
||||
src);
|
||||
|
||||
if (error) {
|
||||
chromeos_laptop_destroy(cros_laptop);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
return cros_laptop;
|
||||
}
|
||||
|
||||
static int __init chromeos_laptop_init(void)
|
||||
{
|
||||
const struct dmi_system_id *dmi_id;
|
||||
@ -652,21 +897,33 @@ static int __init chromeos_laptop_init(void)
|
||||
if (IS_ERR(cros_laptop))
|
||||
return PTR_ERR(cros_laptop);
|
||||
|
||||
if (!cros_laptop->num_i2c_peripherals &&
|
||||
!cros_laptop->num_acpi_peripherals) {
|
||||
pr_debug("no relevant devices detected\n");
|
||||
error = -ENODEV;
|
||||
goto err_destroy_cros_laptop;
|
||||
}
|
||||
|
||||
error = bus_register_notifier(&i2c_bus_type,
|
||||
&chromeos_laptop_i2c_notifier);
|
||||
if (error) {
|
||||
pr_err("failed to register i2c bus notifier: %d\n", error);
|
||||
chromeos_laptop_destroy(cros_laptop);
|
||||
return error;
|
||||
pr_err("failed to register i2c bus notifier: %d\n",
|
||||
error);
|
||||
goto err_destroy_cros_laptop;
|
||||
}
|
||||
|
||||
/*
|
||||
* Scan adapters that have been registered before we installed
|
||||
* the notifier to make sure we do not miss any devices.
|
||||
* Scan adapters that have been registered and clients that have
|
||||
* been created before we installed the notifier to make sure
|
||||
* we do not miss any devices.
|
||||
*/
|
||||
i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter);
|
||||
i2c_for_each_dev(NULL, chromeos_laptop_scan_peripherals);
|
||||
|
||||
return 0;
|
||||
|
||||
err_destroy_cros_laptop:
|
||||
chromeos_laptop_destroy(cros_laptop);
|
||||
return error;
|
||||
}
|
||||
|
||||
static void __exit chromeos_laptop_exit(void)
|
||||
|
111
drivers/platform/chrome/chromeos_tbmc.c
Normal file
111
drivers/platform/chrome/chromeos_tbmc.c
Normal file
@ -0,0 +1,111 @@
|
||||
// SPDX-License-Identifier: GPL-2.0+
|
||||
// Driver to detect Tablet Mode for ChromeOS convertible.
|
||||
//
|
||||
// Copyright (C) 2017 Google, Inc.
|
||||
// Author: Gwendal Grignou <gwendal@chromium.org>
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/input.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/printk.h>
|
||||
|
||||
#define DRV_NAME "chromeos_tbmc"
|
||||
#define ACPI_DRV_NAME "GOOG0006"
|
||||
|
||||
static int chromeos_tbmc_query_switch(struct acpi_device *adev,
|
||||
struct input_dev *idev)
|
||||
{
|
||||
unsigned long long state;
|
||||
acpi_status status;
|
||||
|
||||
status = acpi_evaluate_integer(adev->handle, "TBMC", NULL, &state);
|
||||
if (ACPI_FAILURE(status))
|
||||
return -ENODEV;
|
||||
|
||||
/* input layer checks if event is redundant */
|
||||
input_report_switch(idev, SW_TABLET_MODE, state);
|
||||
input_sync(idev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int chromeos_tbmc_resume(struct device *dev)
|
||||
{
|
||||
struct acpi_device *adev = to_acpi_device(dev);
|
||||
|
||||
return chromeos_tbmc_query_switch(adev, adev->driver_data);
|
||||
}
|
||||
|
||||
static void chromeos_tbmc_notify(struct acpi_device *adev, u32 event)
|
||||
{
|
||||
switch (event) {
|
||||
case 0x80:
|
||||
chromeos_tbmc_query_switch(adev, adev->driver_data);
|
||||
break;
|
||||
default:
|
||||
dev_err(&adev->dev, "Unexpected event: 0x%08X\n", event);
|
||||
}
|
||||
}
|
||||
|
||||
static int chromeos_tbmc_open(struct input_dev *idev)
|
||||
{
|
||||
struct acpi_device *adev = input_get_drvdata(idev);
|
||||
|
||||
return chromeos_tbmc_query_switch(adev, idev);
|
||||
}
|
||||
|
||||
static int chromeos_tbmc_add(struct acpi_device *adev)
|
||||
{
|
||||
struct input_dev *idev;
|
||||
struct device *dev = &adev->dev;
|
||||
int ret;
|
||||
|
||||
idev = devm_input_allocate_device(dev);
|
||||
if (!idev)
|
||||
return -ENOMEM;
|
||||
|
||||
idev->name = "Tablet Mode Switch";
|
||||
idev->phys = acpi_device_hid(adev);
|
||||
|
||||
idev->id.bustype = BUS_HOST;
|
||||
idev->id.version = 1;
|
||||
idev->id.product = 0;
|
||||
idev->open = chromeos_tbmc_open;
|
||||
|
||||
input_set_drvdata(idev, adev);
|
||||
adev->driver_data = idev;
|
||||
|
||||
input_set_capability(idev, EV_SW, SW_TABLET_MODE);
|
||||
ret = input_register_device(idev);
|
||||
if (ret) {
|
||||
dev_err(dev, "cannot register input device\n");
|
||||
return ret;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id chromeos_tbmc_acpi_device_ids[] = {
|
||||
{ ACPI_DRV_NAME, 0 },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, chromeos_tbmc_acpi_device_ids);
|
||||
|
||||
static const SIMPLE_DEV_PM_OPS(chromeos_tbmc_pm_ops, NULL,
|
||||
chromeos_tbmc_resume);
|
||||
|
||||
static struct acpi_driver chromeos_tbmc_driver = {
|
||||
.name = DRV_NAME,
|
||||
.class = DRV_NAME,
|
||||
.ids = chromeos_tbmc_acpi_device_ids,
|
||||
.ops = {
|
||||
.add = chromeos_tbmc_add,
|
||||
.notify = chromeos_tbmc_notify,
|
||||
},
|
||||
.drv.pm = &chromeos_tbmc_pm_ops,
|
||||
};
|
||||
|
||||
module_acpi_driver(chromeos_tbmc_driver);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
MODULE_DESCRIPTION("ChromeOS ACPI tablet switch driver");
|
@ -170,8 +170,7 @@ static ssize_t version_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
uint32_t version = 0, flags = 0;
|
||||
struct cros_ec_dev *ec = container_of(dev,
|
||||
struct cros_ec_dev, class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
int ret;
|
||||
|
||||
ret = lb_throttle();
|
||||
@ -193,8 +192,7 @@ static ssize_t brightness_store(struct device *dev,
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
unsigned int val;
|
||||
struct cros_ec_dev *ec = container_of(dev,
|
||||
struct cros_ec_dev, class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
|
||||
if (kstrtouint(buf, 0, &val))
|
||||
return -EINVAL;
|
||||
@ -238,8 +236,7 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr,
|
||||
{
|
||||
struct ec_params_lightbar *param;
|
||||
struct cros_ec_command *msg;
|
||||
struct cros_ec_dev *ec = container_of(dev,
|
||||
struct cros_ec_dev, class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
unsigned int val[4];
|
||||
int ret, i = 0, j = 0, ok = 0;
|
||||
|
||||
@ -311,8 +308,7 @@ static ssize_t sequence_show(struct device *dev,
|
||||
struct ec_response_lightbar *resp;
|
||||
struct cros_ec_command *msg;
|
||||
int ret;
|
||||
struct cros_ec_dev *ec = container_of(dev,
|
||||
struct cros_ec_dev, class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
|
||||
msg = alloc_lightbar_cmd_msg(ec);
|
||||
if (!msg)
|
||||
@ -439,8 +435,7 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
|
||||
struct cros_ec_command *msg;
|
||||
unsigned int num;
|
||||
int ret, len;
|
||||
struct cros_ec_dev *ec = container_of(dev,
|
||||
struct cros_ec_dev, class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
|
||||
for (len = 0; len < count; len++)
|
||||
if (!isalnum(buf[len]))
|
||||
@ -488,8 +483,7 @@ static ssize_t program_store(struct device *dev, struct device_attribute *attr,
|
||||
int extra_bytes, max_size, ret;
|
||||
struct ec_params_lightbar *param;
|
||||
struct cros_ec_command *msg;
|
||||
struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
|
||||
class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
|
||||
/*
|
||||
* We might need to reject the program for size reasons. The EC
|
||||
@ -599,8 +593,7 @@ static umode_t cros_ec_lightbar_attrs_are_visible(struct kobject *kobj,
|
||||
struct attribute *a, int n)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct cros_ec_dev *ec = container_of(dev,
|
||||
struct cros_ec_dev, class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
struct platform_device *pdev = to_platform_device(ec->dev);
|
||||
struct cros_ec_platform *pdata = pdev->dev.platform_data;
|
||||
int is_cros_ec;
|
||||
|
@ -435,7 +435,13 @@ static int __init cros_ec_lpc_init(void)
|
||||
int ret;
|
||||
acpi_status status;
|
||||
|
||||
if (!dmi_check_system(cros_ec_lpc_dmi_table)) {
|
||||
status = acpi_get_devices(ACPI_DRV_NAME, cros_ec_lpc_parse_device,
|
||||
&cros_ec_lpc_acpi_device_found, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_warn(DRV_NAME ": Looking for %s failed\n", ACPI_DRV_NAME);
|
||||
|
||||
if (!cros_ec_lpc_acpi_device_found &&
|
||||
!dmi_check_system(cros_ec_lpc_dmi_table)) {
|
||||
pr_err(DRV_NAME ": unsupported system.\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -450,11 +456,6 @@ static int __init cros_ec_lpc_init(void)
|
||||
return ret;
|
||||
}
|
||||
|
||||
status = acpi_get_devices(ACPI_DRV_NAME, cros_ec_lpc_parse_device,
|
||||
&cros_ec_lpc_acpi_device_found, NULL);
|
||||
if (ACPI_FAILURE(status))
|
||||
pr_warn(DRV_NAME ": Looking for %s failed\n", ACPI_DRV_NAME);
|
||||
|
||||
if (!cros_ec_lpc_acpi_device_found) {
|
||||
/* Register the device, and it'll get hooked up automatically */
|
||||
ret = platform_device_register(&cros_ec_lpc_device);
|
||||
|
@ -34,8 +34,6 @@
|
||||
#include <linux/types.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#define to_cros_ec_dev(dev) container_of(dev, struct cros_ec_dev, class_dev)
|
||||
|
||||
/* Accessor functions */
|
||||
|
||||
static ssize_t reboot_show(struct device *dev,
|
||||
|
@ -29,8 +29,7 @@ static ssize_t vboot_context_read(struct file *filp, struct kobject *kobj,
|
||||
loff_t pos, size_t count)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
|
||||
class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
struct cros_ec_device *ecdev = ec->ec_dev;
|
||||
struct ec_params_vbnvcontext *params;
|
||||
struct cros_ec_command *msg;
|
||||
@ -70,8 +69,7 @@ static ssize_t vboot_context_write(struct file *filp, struct kobject *kobj,
|
||||
loff_t pos, size_t count)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
|
||||
class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
struct cros_ec_device *ecdev = ec->ec_dev;
|
||||
struct ec_params_vbnvcontext *params;
|
||||
struct cros_ec_command *msg;
|
||||
@ -111,8 +109,7 @@ static umode_t cros_ec_vbc_is_visible(struct kobject *kobj,
|
||||
struct bin_attribute *a, int n)
|
||||
{
|
||||
struct device *dev = container_of(kobj, struct device, kobj);
|
||||
struct cros_ec_dev *ec = container_of(dev, struct cros_ec_dev,
|
||||
class_dev);
|
||||
struct cros_ec_dev *ec = to_cros_ec_dev(dev);
|
||||
struct device_node *np = ec->ec_dev->dev->of_node;
|
||||
|
||||
if (IS_ENABLED(CONFIG_OF) && np) {
|
||||
|
@ -197,6 +197,8 @@ struct cros_ec_dev {
|
||||
u32 features[2];
|
||||
};
|
||||
|
||||
#define to_cros_ec_dev(dev) container_of(dev, struct cros_ec_dev, class_dev)
|
||||
|
||||
/**
|
||||
* cros_ec_suspend - Handle a suspend operation for the ChromeOS EC device
|
||||
*
|
||||
|
Loading…
Reference in New Issue
Block a user