Commit e9e352e9 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/chrome-platform

Pull chrome platform cleanups and improvements from Olof Johansson:
 - Use deferred probing on Chrome OS platforms for the i2c device
   registration.  This fixes a long-standing race of initialization of
   touchpad/screen on Chromebooks.
 - Added in platform device registration for pstore console on supported
   hardware
 - Misc smaller fixes (__initdata, module exit cleanup, etc)

* tag 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/olof/chrome-platform:
  platform/chrome: unregister platform driver/device when module exit
  platform/chrome: Make i2c_adapter_names static
  platform/chrome: chromeos_laptop - fix incorrect placement of __initdata tag
  platform/chrome: chromeos_laptop - Use deferred probing
  platform/chrome: chromeos_laptop - Restructure device associations
  platform/chrome: Add pstore platform_device
parents b3a4bcaa 2b8454a7
......@@ -25,4 +25,18 @@ config CHROMEOS_LAPTOP
If you have a supported Chromebook, choose Y or M here.
The module will be called chromeos_laptop.
config CHROMEOS_PSTORE
tristate "Chrome OS pstore support"
---help---
This module instantiates the persistent storage on x86 ChromeOS
devices. It can be used to store away console logs and crash
information across reboots.
The range of memory used is 0xf00000-0x1000000, traditionally
the memory used to back VGA controller memory.
If you have a supported Chromebook, choose Y or M here.
The module will be called chromeos_pstore.
endif # CHROMEOS_PLATFORMS
obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
......@@ -27,6 +27,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#define ATMEL_TP_I2C_ADDR 0x4b
#define ATMEL_TP_I2C_BL_ADDR 0x25
......@@ -40,7 +41,7 @@ static struct i2c_client *als;
static struct i2c_client *tp;
static struct i2c_client *ts;
const char *i2c_adapter_names[] = {
static const char *i2c_adapter_names[] = {
"SMBus I801 adapter",
"i915 gmbus vga",
"i915 gmbus panel",
......@@ -53,20 +54,33 @@ enum i2c_adapter_type {
I2C_ADAPTER_PANEL,
};
static struct i2c_board_info __initdata cyapa_device = {
struct i2c_peripheral {
int (*add)(enum i2c_adapter_type type);
enum i2c_adapter_type type;
};
#define MAX_I2C_PERIPHERALS 3
struct chromeos_laptop {
struct i2c_peripheral i2c_peripherals[MAX_I2C_PERIPHERALS];
};
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 __initdata isl_als_device = {
static struct i2c_board_info isl_als_device = {
I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR),
};
static struct i2c_board_info __initdata tsl2583_als_device = {
static struct i2c_board_info tsl2583_als_device = {
I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR),
};
static struct i2c_board_info __initdata tsl2563_als_device = {
static struct i2c_board_info tsl2563_als_device = {
I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR),
};
......@@ -89,7 +103,7 @@ static struct mxt_platform_data atmel_224s_tp_platform_data = {
.config_length = 0,
};
static struct i2c_board_info __initdata atmel_224s_tp_device = {
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,
......@@ -110,13 +124,13 @@ static struct mxt_platform_data atmel_1664s_platform_data = {
.config_length = 0,
};
static struct i2c_board_info __initdata atmel_1664s_device = {
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 struct i2c_client __init *__add_probed_i2c_device(
static struct i2c_client *__add_probed_i2c_device(
const char *name,
int bus,
struct i2c_board_info *info,
......@@ -169,7 +183,7 @@ static struct i2c_client __init *__add_probed_i2c_device(
return client;
}
static int __init __find_i2c_adap(struct device *dev, void *data)
static int __find_i2c_adap(struct device *dev, void *data)
{
const char *name = data;
static const char *prefix = "i2c-";
......@@ -180,7 +194,7 @@ static int __init __find_i2c_adap(struct device *dev, void *data)
return (strncmp(adapter->name, name, strlen(name)) == 0);
}
static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
static int find_i2c_adapter_num(enum i2c_adapter_type type)
{
struct device *dev = NULL;
struct i2c_adapter *adapter;
......@@ -189,7 +203,8 @@ static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
dev = bus_find_device(&i2c_bus_type, NULL, (void *)name,
__find_i2c_adap);
if (!dev) {
pr_err("%s: i2c adapter %s not found on system.\n", __func__,
/* Adapters may appear later. Deferred probing will retry */
pr_notice("%s: i2c adapter %s not found on system.\n", __func__,
name);
return -ENODEV;
}
......@@ -205,7 +220,7 @@ static int __init find_i2c_adapter_num(enum i2c_adapter_type type)
* Returns NULL if no devices found.
* See Documentation/i2c/instantiating-devices for more information.
*/
static __init struct i2c_client *add_probed_i2c_device(
static struct i2c_client *add_probed_i2c_device(
const char *name,
enum i2c_adapter_type type,
struct i2c_board_info *info,
......@@ -222,7 +237,7 @@ static __init struct i2c_client *add_probed_i2c_device(
* info->addr.
* Returns NULL if no device found.
*/
static __init struct i2c_client *add_i2c_device(const char *name,
static struct i2c_client *add_i2c_device(const char *name,
enum i2c_adapter_type type,
struct i2c_board_info *info)
{
......@@ -233,161 +248,259 @@ static __init struct i2c_client *add_i2c_device(const char *name,
addr_list);
}
static struct i2c_client __init *add_smbus_device(const char *name,
struct i2c_board_info *info)
{
return add_i2c_device(name, I2C_ADAPTER_SMBUS, info);
}
static int __init setup_cyapa_smbus_tp(const struct dmi_system_id *id)
static int setup_cyapa_tp(enum i2c_adapter_type type)
{
/* add cyapa touchpad on smbus */
tp = add_smbus_device("trackpad", &cyapa_device);
if (tp)
return 0;
/* add cyapa touchpad */
tp = add_i2c_device("trackpad", type, &cyapa_device);
return (!tp) ? -EAGAIN : 0;
}
static int __init setup_atmel_224s_tp(const struct dmi_system_id *id)
static int setup_atmel_224s_tp(enum i2c_adapter_type type)
{
const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR,
ATMEL_TP_I2C_ADDR,
I2C_CLIENT_END };
if (tp)
return 0;
/* add atmel mxt touchpad on VGA DDC GMBus */
tp = add_probed_i2c_device("trackpad", I2C_ADAPTER_VGADDC,
/* add atmel mxt touchpad */
tp = add_probed_i2c_device("trackpad", type,
&atmel_224s_tp_device, addr_list);
return 0;
return (!tp) ? -EAGAIN : 0;
}
static int __init setup_atmel_1664s_ts(const struct dmi_system_id *id)
static int setup_atmel_1664s_ts(enum i2c_adapter_type type)
{
const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR,
ATMEL_TS_I2C_ADDR,
I2C_CLIENT_END };
if (ts)
return 0;
/* add atmel mxt touch device on PANEL GMBus */
ts = add_probed_i2c_device("touchscreen", I2C_ADAPTER_PANEL,
/* add atmel mxt touch device */
ts = add_probed_i2c_device("touchscreen", type,
&atmel_1664s_device, addr_list);
return 0;
return (!ts) ? -EAGAIN : 0;
}
static int __init setup_isl29018_als(const struct dmi_system_id *id)
static int setup_isl29018_als(enum i2c_adapter_type type)
{
/* add isl29018 light sensor */
als = add_smbus_device("lightsensor", &isl_als_device);
if (als)
return 0;
/* add isl29018 light sensor */
als = add_i2c_device("lightsensor", type, &isl_als_device);
return (!als) ? -EAGAIN : 0;
}
static int __init setup_isl29023_als(const struct dmi_system_id *id)
static int setup_tsl2583_als(enum i2c_adapter_type type)
{
/* add isl29023 light sensor on Panel GMBus */
als = add_i2c_device("lightsensor", I2C_ADAPTER_PANEL,
&isl_als_device);
if (als)
return 0;
/* add tsl2583 light sensor */
als = add_i2c_device(NULL, type, &tsl2583_als_device);
return (!als) ? -EAGAIN : 0;
}
static int __init setup_tsl2583_als(const struct dmi_system_id *id)
static int setup_tsl2563_als(enum i2c_adapter_type type)
{
/* add tsl2583 light sensor on smbus */
als = add_smbus_device(NULL, &tsl2583_als_device);
if (als)
return 0;
/* add tsl2563 light sensor */
als = add_i2c_device(NULL, type, &tsl2563_als_device);
return (!als) ? -EAGAIN : 0;
}
static int __init setup_tsl2563_als(const struct dmi_system_id *id)
static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id)
{
/* add tsl2563 light sensor on smbus */
als = add_smbus_device(NULL, &tsl2563_als_device);
return 0;
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 struct dmi_system_id __initdata chromeos_laptop_dmi_table[] = {
{
.ident = "Samsung Series 5 550 - Touchpad",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
static int chromeos_laptop_probe(struct platform_device *pdev)
{
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)
break;
/* Add the device. Set -EPROBE_DEFER on any failure */
if (i2c_dev->add(i2c_dev->type))
ret = -EPROBE_DEFER;
}
return ret;
}
static struct chromeos_laptop samsung_series_5_550 = {
.i2c_peripherals = {
/* Touchpad. */
{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
/* Light Sensor. */
{ .add = setup_isl29018_als, I2C_ADAPTER_SMBUS },
},
.callback = setup_cyapa_smbus_tp,
};
static struct chromeos_laptop samsung_series_5 = {
.i2c_peripherals = {
/* Light Sensor. */
{ .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS },
},
{
.ident = "Chromebook Pixel - Touchscreen",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
};
static struct chromeos_laptop chromebook_pixel = {
.i2c_peripherals = {
/* Touch Screen. */
{ .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL },
/* Touchpad. */
{ .add = setup_atmel_224s_tp, I2C_ADAPTER_VGADDC },
/* Light Sensor. */
{ .add = setup_isl29018_als, I2C_ADAPTER_PANEL },
},
.callback = setup_atmel_1664s_ts,
};
static struct chromeos_laptop acer_c7_chromebook = {
.i2c_peripherals = {
/* Touchpad. */
{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
},
{
.ident = "Chromebook Pixel - Touchpad",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
};
static struct chromeos_laptop acer_ac700 = {
.i2c_peripherals = {
/* Light Sensor. */
{ .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
},
};
static struct chromeos_laptop hp_pavilion_14_chromebook = {
.i2c_peripherals = {
/* Touchpad. */
{ .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS },
},
.callback = setup_atmel_224s_tp,
};
static struct chromeos_laptop cr48 = {
.i2c_peripherals = {
/* Light Sensor. */
{ .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS },
},
};
#define _CBDD(board_) \
.callback = chromeos_laptop_dmi_matched, \
.driver_data = (void *)&board_
static struct dmi_system_id chromeos_laptop_dmi_table[] __initdata = {
{
.ident = "Samsung Series 5 550 - Light Sensor",
.ident = "Samsung Series 5 550",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"),
},
.callback = setup_isl29018_als,
_CBDD(samsung_series_5_550),
},
{
.ident = "Chromebook Pixel - Light Sensor",
.ident = "Samsung Series 5",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
},
.callback = setup_isl29023_als,
_CBDD(samsung_series_5),
},
{
.ident = "Acer C7 Chromebook - Touchpad",
.ident = "Chromebook Pixel",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
DMI_MATCH(DMI_PRODUCT_NAME, "Link"),
},
.callback = setup_cyapa_smbus_tp,
_CBDD(chromebook_pixel),
},
{
.ident = "HP Pavilion 14 Chromebook - Touchpad",
.ident = "Acer C7 Chromebook",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"),
},
.callback = setup_cyapa_smbus_tp,
_CBDD(acer_c7_chromebook),
},
{
.ident = "Samsung Series 5 - Light Sensor",
.ident = "Acer AC700",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
},
.callback = setup_tsl2583_als,
_CBDD(acer_ac700),
},
{
.ident = "Cr-48 - Light Sensor",
.ident = "HP Pavilion 14 Chromebook",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"),
},
.callback = setup_tsl2563_als,
_CBDD(hp_pavilion_14_chromebook),
},
{
.ident = "Acer AC700 - Light Sensor",
.ident = "Cr-48",
.matches = {
DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
},
.callback = setup_tsl2563_als,
_CBDD(cr48),
},
{ }
};
MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
static struct platform_device *cros_platform_device;
static struct platform_driver cros_platform_driver = {
.driver = {
.name = "chromeos_laptop",
.owner = THIS_MODULE,
},
.probe = chromeos_laptop_probe,
};
static int __init chromeos_laptop_init(void)
{
int ret;
if (!dmi_check_system(chromeos_laptop_dmi_table)) {
pr_debug("%s unsupported system.\n", __func__);
return -ENODEV;
}
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;
}
ret = platform_device_add(cros_platform_device);
if (ret)
goto fail_platform_device2;
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)
......@@ -398,6 +511,9 @@ static void __exit chromeos_laptop_exit(void)
i2c_unregister_device(tp);
if (ts)
i2c_unregister_device(ts);
platform_device_unregister(cros_platform_device);
platform_driver_unregister(&cros_platform_driver);
}
module_init(chromeos_laptop_init);
......
/*
* chromeos_pstore.c - Driver to instantiate Chromebook ramoops device
*
* Copyright (C) 2013 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, version 2 of the License.
*/
#include <linux/dmi.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pstore_ram.h>
static struct dmi_system_id chromeos_pstore_dmi_table[] __initdata = {
{
/*
* Today all Chromebooks/boxes ship with GOOGLE as vendor and
* coreboot as bios vendor. No other systems with this
* combination are known to date.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
},
},
{
/*
* The first Samsung Chromebox and Chromebook Series 5 550 use
* coreboot but with Samsung as the system vendor.
*/
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"),
DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"),
},
},
{
/* x86-alex, the first Samsung Chromebook. */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG ELECTRONICS CO., LTD."),
DMI_MATCH(DMI_PRODUCT_NAME, "Alex"),
},
},
{
/* x86-mario, the Cr-48 pilot device from Google. */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "IEC"),
DMI_MATCH(DMI_PRODUCT_NAME, "Mario"),
},
},
{
/* x86-zgb, the first Acer Chromebook. */
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "ACER"),
DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"),
},
},
{ }
};
MODULE_DEVICE_TABLE(dmi, chromeos_pstore_dmi_table);
/*
* On x86 chromebooks/boxes, the firmware will keep the legacy VGA memory
* range untouched across reboots, so we use that to store our pstore
* contents for panic logs, etc.
*/
static struct ramoops_platform_data chromeos_ramoops_data = {
.mem_size = 0x100000,
.mem_address = 0xf00000,
.record_size = 0x20000,
.console_size = 0x20000,
.ftrace_size = 0x20000,
.dump_oops = 1,
};
static struct platform_device chromeos_ramoops = {
.name = "ramoops",
.dev = {
.platform_data = &chromeos_ramoops_data,
},
};
static int __init chromeos_pstore_init(void)
{
if (dmi_check_system(chromeos_pstore_dmi_table))
return platform_device_register(&chromeos_ramoops);
return -ENODEV;
}
static void __exit chromeos_pstore_exit(void)
{
platform_device_unregister(&chromeos_ramoops);
}
module_init(chromeos_pstore_init);
module_exit(chromeos_pstore_exit);
MODULE_DESCRIPTION("Chrome OS pstore module");
MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment