diff options
author | Benson Leung <bleung@chromium.org> | 2018-04-10 02:00:04 -0400 |
---|---|---|
committer | Benson Leung <bleung@chromium.org> | 2018-04-10 02:00:04 -0400 |
commit | 72655f6cf7fe04b867776bb7120fbdb84dee4f61 (patch) | |
tree | 000347fc0721362eb43b0449f1b3484f2696ad3b | |
parent | f56db262e46d3368ee4e5c9e19797853cab382cd (diff) | |
parent | 96a938aa214e965d5b4a2f10443b29cad14289b9 (diff) |
Merge remote-tracking branch 'chrome-platform-stop-being-a-platform-driver-plus-atmel_mxt_ts-for-v4.17' into working-branch-for-4.17
-rw-r--r-- | MAINTAINERS | 1 | ||||
-rw-r--r-- | drivers/input/touchscreen/atmel_mxt_ts.c | 231 | ||||
-rw-r--r-- | drivers/platform/chrome/chromeos_laptop.c | 896 | ||||
-rw-r--r-- | include/linux/platform_data/atmel_mxt_ts.h | 31 |
4 files changed, 579 insertions, 580 deletions
diff --git a/MAINTAINERS b/MAINTAINERS index 73c0cdabf755..d4b0b09d2e3f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -2394,7 +2394,6 @@ T: git git://github.com/ndyer/linux.git | |||
2394 | S: Maintained | 2394 | S: Maintained |
2395 | F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt | 2395 | F: Documentation/devicetree/bindings/input/atmel,maxtouch.txt |
2396 | F: drivers/input/touchscreen/atmel_mxt_ts.c | 2396 | F: drivers/input/touchscreen/atmel_mxt_ts.c |
2397 | F: include/linux/platform_data/atmel_mxt_ts.h | ||
2398 | 2397 | ||
2399 | ATMEL SAMA5D2 ADC DRIVER | 2398 | ATMEL SAMA5D2 ADC DRIVER |
2400 | M: Ludovic Desroches <ludovic.desroches@microchip.com> | 2399 | 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 7659bc48f1db..5d9699fe1b55 100644 --- a/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/drivers/input/touchscreen/atmel_mxt_ts.c | |||
@@ -23,12 +23,13 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/firmware.h> | 24 | #include <linux/firmware.h> |
25 | #include <linux/i2c.h> | 25 | #include <linux/i2c.h> |
26 | #include <linux/platform_data/atmel_mxt_ts.h> | ||
27 | #include <linux/input/mt.h> | 26 | #include <linux/input/mt.h> |
28 | #include <linux/interrupt.h> | 27 | #include <linux/interrupt.h> |
29 | #include <linux/of.h> | 28 | #include <linux/of.h> |
29 | #include <linux/property.h> | ||
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/gpio/consumer.h> | 31 | #include <linux/gpio/consumer.h> |
32 | #include <linux/property.h> | ||
32 | #include <asm/unaligned.h> | 33 | #include <asm/unaligned.h> |
33 | #include <media/v4l2-device.h> | 34 | #include <media/v4l2-device.h> |
34 | #include <media/v4l2-ioctl.h> | 35 | #include <media/v4l2-ioctl.h> |
@@ -268,12 +269,16 @@ static const struct v4l2_file_operations mxt_video_fops = { | |||
268 | .poll = vb2_fop_poll, | 269 | .poll = vb2_fop_poll, |
269 | }; | 270 | }; |
270 | 271 | ||
272 | enum mxt_suspend_mode { | ||
273 | MXT_SUSPEND_DEEP_SLEEP = 0, | ||
274 | MXT_SUSPEND_T9_CTRL = 1, | ||
275 | }; | ||
276 | |||
271 | /* Each client has this additional data */ | 277 | /* Each client has this additional data */ |
272 | struct mxt_data { | 278 | struct mxt_data { |
273 | struct i2c_client *client; | 279 | struct i2c_client *client; |
274 | struct input_dev *input_dev; | 280 | struct input_dev *input_dev; |
275 | char phys[64]; /* device physical location */ | 281 | char phys[64]; /* device physical location */ |
276 | const struct mxt_platform_data *pdata; | ||
277 | struct mxt_object *object_table; | 282 | struct mxt_object *object_table; |
278 | struct mxt_info info; | 283 | struct mxt_info info; |
279 | unsigned int irq; | 284 | unsigned int irq; |
@@ -324,6 +329,11 @@ struct mxt_data { | |||
324 | 329 | ||
325 | /* for config update handling */ | 330 | /* for config update handling */ |
326 | struct completion crc_completion; | 331 | struct completion crc_completion; |
332 | |||
333 | u32 *t19_keymap; | ||
334 | unsigned int t19_num_keys; | ||
335 | |||
336 | enum mxt_suspend_mode suspend_mode; | ||
327 | }; | 337 | }; |
328 | 338 | ||
329 | struct mxt_vb2_buffer { | 339 | struct mxt_vb2_buffer { |
@@ -742,15 +752,14 @@ static int mxt_write_object(struct mxt_data *data, | |||
742 | static void mxt_input_button(struct mxt_data *data, u8 *message) | 752 | static void mxt_input_button(struct mxt_data *data, u8 *message) |
743 | { | 753 | { |
744 | struct input_dev *input = data->input_dev; | 754 | struct input_dev *input = data->input_dev; |
745 | const struct mxt_platform_data *pdata = data->pdata; | ||
746 | int i; | 755 | int i; |
747 | 756 | ||
748 | for (i = 0; i < pdata->t19_num_keys; i++) { | 757 | for (i = 0; i < data->t19_num_keys; i++) { |
749 | if (pdata->t19_keymap[i] == KEY_RESERVED) | 758 | if (data->t19_keymap[i] == KEY_RESERVED) |
750 | continue; | 759 | continue; |
751 | 760 | ||
752 | /* Active-low switch */ | 761 | /* Active-low switch */ |
753 | input_report_key(input, pdata->t19_keymap[i], | 762 | input_report_key(input, data->t19_keymap[i], |
754 | !(message[1] & BIT(i))); | 763 | !(message[1] & BIT(i))); |
755 | } | 764 | } |
756 | } | 765 | } |
@@ -758,7 +767,7 @@ static void mxt_input_button(struct mxt_data *data, u8 *message) | |||
758 | static void mxt_input_sync(struct mxt_data *data) | 767 | static void mxt_input_sync(struct mxt_data *data) |
759 | { | 768 | { |
760 | input_mt_report_pointer_emulation(data->input_dev, | 769 | input_mt_report_pointer_emulation(data->input_dev, |
761 | data->pdata->t19_num_keys); | 770 | data->t19_num_keys); |
762 | input_sync(data->input_dev); | 771 | input_sync(data->input_dev); |
763 | } | 772 | } |
764 | 773 | ||
@@ -1858,7 +1867,6 @@ static void mxt_input_close(struct input_dev *dev); | |||
1858 | static void mxt_set_up_as_touchpad(struct input_dev *input_dev, | 1867 | static void mxt_set_up_as_touchpad(struct input_dev *input_dev, |
1859 | struct mxt_data *data) | 1868 | struct mxt_data *data) |
1860 | { | 1869 | { |
1861 | const struct mxt_platform_data *pdata = data->pdata; | ||
1862 | int i; | 1870 | int i; |
1863 | 1871 | ||
1864 | input_dev->name = "Atmel maXTouch Touchpad"; | 1872 | input_dev->name = "Atmel maXTouch Touchpad"; |
@@ -1872,15 +1880,14 @@ static void mxt_set_up_as_touchpad(struct input_dev *input_dev, | |||
1872 | input_abs_set_res(input_dev, ABS_MT_POSITION_Y, | 1880 | input_abs_set_res(input_dev, ABS_MT_POSITION_Y, |
1873 | MXT_PIXELS_PER_MM); | 1881 | MXT_PIXELS_PER_MM); |
1874 | 1882 | ||
1875 | for (i = 0; i < pdata->t19_num_keys; i++) | 1883 | for (i = 0; i < data->t19_num_keys; i++) |
1876 | if (pdata->t19_keymap[i] != KEY_RESERVED) | 1884 | if (data->t19_keymap[i] != KEY_RESERVED) |
1877 | input_set_capability(input_dev, EV_KEY, | 1885 | input_set_capability(input_dev, EV_KEY, |
1878 | pdata->t19_keymap[i]); | 1886 | data->t19_keymap[i]); |
1879 | } | 1887 | } |
1880 | 1888 | ||
1881 | static int mxt_initialize_input_device(struct mxt_data *data) | 1889 | static int mxt_initialize_input_device(struct mxt_data *data) |
1882 | { | 1890 | { |
1883 | const struct mxt_platform_data *pdata = data->pdata; | ||
1884 | struct device *dev = &data->client->dev; | 1891 | struct device *dev = &data->client->dev; |
1885 | struct input_dev *input_dev; | 1892 | struct input_dev *input_dev; |
1886 | int error; | 1893 | int error; |
@@ -1946,7 +1953,7 @@ static int mxt_initialize_input_device(struct mxt_data *data) | |||
1946 | } | 1953 | } |
1947 | 1954 | ||
1948 | /* If device has buttons we assume it is a touchpad */ | 1955 | /* If device has buttons we assume it is a touchpad */ |
1949 | if (pdata->t19_num_keys) { | 1956 | if (data->t19_num_keys) { |
1950 | mxt_set_up_as_touchpad(input_dev, data); | 1957 | mxt_set_up_as_touchpad(input_dev, data); |
1951 | mt_flags |= INPUT_MT_POINTER; | 1958 | mt_flags |= INPUT_MT_POINTER; |
1952 | } else { | 1959 | } else { |
@@ -2868,7 +2875,7 @@ static const struct attribute_group mxt_attr_group = { | |||
2868 | 2875 | ||
2869 | static void mxt_start(struct mxt_data *data) | 2876 | static void mxt_start(struct mxt_data *data) |
2870 | { | 2877 | { |
2871 | switch (data->pdata->suspend_mode) { | 2878 | switch (data->suspend_mode) { |
2872 | case MXT_SUSPEND_T9_CTRL: | 2879 | case MXT_SUSPEND_T9_CTRL: |
2873 | mxt_soft_reset(data); | 2880 | mxt_soft_reset(data); |
2874 | 2881 | ||
@@ -2886,12 +2893,11 @@ static void mxt_start(struct mxt_data *data) | |||
2886 | mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); | 2893 | mxt_t6_command(data, MXT_COMMAND_CALIBRATE, 1, false); |
2887 | break; | 2894 | break; |
2888 | } | 2895 | } |
2889 | |||
2890 | } | 2896 | } |
2891 | 2897 | ||
2892 | static void mxt_stop(struct mxt_data *data) | 2898 | static void mxt_stop(struct mxt_data *data) |
2893 | { | 2899 | { |
2894 | switch (data->pdata->suspend_mode) { | 2900 | switch (data->suspend_mode) { |
2895 | case MXT_SUSPEND_T9_CTRL: | 2901 | case MXT_SUSPEND_T9_CTRL: |
2896 | /* Touch disable */ | 2902 | /* Touch disable */ |
2897 | mxt_write_object(data, | 2903 | mxt_write_object(data, |
@@ -2921,55 +2927,49 @@ static void mxt_input_close(struct input_dev *dev) | |||
2921 | mxt_stop(data); | 2927 | mxt_stop(data); |
2922 | } | 2928 | } |
2923 | 2929 | ||
2924 | #ifdef CONFIG_OF | 2930 | static int mxt_parse_device_properties(struct mxt_data *data) |
2925 | static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) | ||
2926 | { | 2931 | { |
2927 | struct mxt_platform_data *pdata; | 2932 | static const char keymap_property[] = "linux,gpio-keymap"; |
2928 | struct device_node *np = client->dev.of_node; | 2933 | struct device *dev = &data->client->dev; |
2929 | u32 *keymap; | 2934 | u32 *keymap; |
2930 | int proplen, ret; | 2935 | int n_keys; |
2931 | 2936 | int error; | |
2932 | if (!np) | ||
2933 | return ERR_PTR(-ENOENT); | ||
2934 | |||
2935 | pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL); | ||
2936 | if (!pdata) | ||
2937 | return ERR_PTR(-ENOMEM); | ||
2938 | 2937 | ||
2939 | if (of_find_property(np, "linux,gpio-keymap", &proplen)) { | 2938 | if (device_property_present(dev, keymap_property)) { |
2940 | pdata->t19_num_keys = proplen / sizeof(u32); | 2939 | n_keys = device_property_read_u32_array(dev, keymap_property, |
2940 | NULL, 0); | ||
2941 | if (n_keys <= 0) { | ||
2942 | error = n_keys < 0 ? n_keys : -EINVAL; | ||
2943 | dev_err(dev, "invalid/malformed '%s' property: %d\n", | ||
2944 | keymap_property, error); | ||
2945 | return error; | ||
2946 | } | ||
2941 | 2947 | ||
2942 | keymap = devm_kzalloc(&client->dev, | 2948 | keymap = devm_kmalloc_array(dev, n_keys, sizeof(*keymap), |
2943 | pdata->t19_num_keys * sizeof(keymap[0]), | 2949 | GFP_KERNEL); |
2944 | GFP_KERNEL); | ||
2945 | if (!keymap) | 2950 | if (!keymap) |
2946 | return ERR_PTR(-ENOMEM); | 2951 | return -ENOMEM; |
2947 | 2952 | ||
2948 | ret = of_property_read_u32_array(np, "linux,gpio-keymap", | 2953 | error = device_property_read_u32_array(dev, keymap_property, |
2949 | keymap, pdata->t19_num_keys); | 2954 | keymap, n_keys); |
2950 | if (ret) | 2955 | if (error) { |
2951 | dev_warn(&client->dev, | 2956 | dev_err(dev, "failed to parse '%s' property: %d\n", |
2952 | "Couldn't read linux,gpio-keymap: %d\n", ret); | 2957 | keymap_property, error); |
2958 | return error; | ||
2959 | } | ||
2953 | 2960 | ||
2954 | pdata->t19_keymap = keymap; | 2961 | data->t19_keymap = keymap; |
2962 | data->t19_num_keys = n_keys; | ||
2955 | } | 2963 | } |
2956 | 2964 | ||
2957 | pdata->suspend_mode = MXT_SUSPEND_DEEP_SLEEP; | 2965 | return 0; |
2958 | |||
2959 | return pdata; | ||
2960 | } | ||
2961 | #else | ||
2962 | static const struct mxt_platform_data *mxt_parse_dt(struct i2c_client *client) | ||
2963 | { | ||
2964 | return ERR_PTR(-ENOENT); | ||
2965 | } | 2966 | } |
2966 | #endif | ||
2967 | 2967 | ||
2968 | #ifdef CONFIG_ACPI | 2968 | #ifdef CONFIG_ACPI |
2969 | 2969 | ||
2970 | struct mxt_acpi_platform_data { | 2970 | struct mxt_acpi_platform_data { |
2971 | const char *hid; | 2971 | const char *hid; |
2972 | struct mxt_platform_data pdata; | 2972 | const struct property_entry *props; |
2973 | }; | 2973 | }; |
2974 | 2974 | ||
2975 | static unsigned int samus_touchpad_buttons[] = { | 2975 | static unsigned int samus_touchpad_buttons[] = { |
@@ -2979,14 +2979,16 @@ static unsigned int samus_touchpad_buttons[] = { | |||
2979 | BTN_LEFT | 2979 | BTN_LEFT |
2980 | }; | 2980 | }; |
2981 | 2981 | ||
2982 | static const struct property_entry samus_touchpad_props[] = { | ||
2983 | PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons), | ||
2984 | { } | ||
2985 | }; | ||
2986 | |||
2982 | static struct mxt_acpi_platform_data samus_platform_data[] = { | 2987 | static struct mxt_acpi_platform_data samus_platform_data[] = { |
2983 | { | 2988 | { |
2984 | /* Touchpad */ | 2989 | /* Touchpad */ |
2985 | .hid = "ATML0000", | 2990 | .hid = "ATML0000", |
2986 | .pdata = { | 2991 | .props = samus_touchpad_props, |
2987 | .t19_num_keys = ARRAY_SIZE(samus_touchpad_buttons), | ||
2988 | .t19_keymap = samus_touchpad_buttons, | ||
2989 | }, | ||
2990 | }, | 2992 | }, |
2991 | { | 2993 | { |
2992 | /* Touchscreen */ | 2994 | /* Touchscreen */ |
@@ -3004,14 +3006,16 @@ static unsigned int chromebook_tp_buttons[] = { | |||
3004 | BTN_LEFT | 3006 | BTN_LEFT |
3005 | }; | 3007 | }; |
3006 | 3008 | ||
3009 | static const struct property_entry chromebook_tp_props[] = { | ||
3010 | PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_tp_buttons), | ||
3011 | { } | ||
3012 | }; | ||
3013 | |||
3007 | static struct mxt_acpi_platform_data chromebook_platform_data[] = { | 3014 | static struct mxt_acpi_platform_data chromebook_platform_data[] = { |
3008 | { | 3015 | { |
3009 | /* Touchpad */ | 3016 | /* Touchpad */ |
3010 | .hid = "ATML0000", | 3017 | .hid = "ATML0000", |
3011 | .pdata = { | 3018 | .props = chromebook_tp_props, |
3012 | .t19_num_keys = ARRAY_SIZE(chromebook_tp_buttons), | ||
3013 | .t19_keymap = chromebook_tp_buttons, | ||
3014 | }, | ||
3015 | }, | 3019 | }, |
3016 | { | 3020 | { |
3017 | /* Touchscreen */ | 3021 | /* Touchscreen */ |
@@ -3041,83 +3045,85 @@ static const struct dmi_system_id mxt_dmi_table[] = { | |||
3041 | { } | 3045 | { } |
3042 | }; | 3046 | }; |
3043 | 3047 | ||
3044 | static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client) | 3048 | static int mxt_prepare_acpi_properties(struct i2c_client *client) |
3045 | { | 3049 | { |
3046 | struct acpi_device *adev; | 3050 | struct acpi_device *adev; |
3047 | const struct dmi_system_id *system_id; | 3051 | const struct dmi_system_id *system_id; |
3048 | const struct mxt_acpi_platform_data *acpi_pdata; | 3052 | const struct mxt_acpi_platform_data *acpi_pdata; |
3049 | 3053 | ||
3050 | /* | ||
3051 | * Ignore ACPI devices representing bootloader mode. | ||
3052 | * | ||
3053 | * This is a bit of a hack: Google Chromebook BIOS creates ACPI | ||
3054 | * devices for both application and bootloader modes, but we are | ||
3055 | * interested in application mode only (if device is in bootloader | ||
3056 | * mode we'll end up switching into application anyway). So far | ||
3057 | * application mode addresses were all above 0x40, so we'll use it | ||
3058 | * as a threshold. | ||
3059 | */ | ||
3060 | if (client->addr < 0x40) | ||
3061 | return ERR_PTR(-ENXIO); | ||
3062 | |||
3063 | adev = ACPI_COMPANION(&client->dev); | 3054 | adev = ACPI_COMPANION(&client->dev); |
3064 | if (!adev) | 3055 | if (!adev) |
3065 | return ERR_PTR(-ENOENT); | 3056 | return -ENOENT; |
3066 | 3057 | ||
3067 | system_id = dmi_first_match(mxt_dmi_table); | 3058 | system_id = dmi_first_match(mxt_dmi_table); |
3068 | if (!system_id) | 3059 | if (!system_id) |
3069 | return ERR_PTR(-ENOENT); | 3060 | return -ENOENT; |
3070 | 3061 | ||
3071 | acpi_pdata = system_id->driver_data; | 3062 | acpi_pdata = system_id->driver_data; |
3072 | if (!acpi_pdata) | 3063 | if (!acpi_pdata) |
3073 | return ERR_PTR(-ENOENT); | 3064 | return -ENOENT; |
3074 | 3065 | ||
3075 | while (acpi_pdata->hid) { | 3066 | while (acpi_pdata->hid) { |
3076 | if (!strcmp(acpi_device_hid(adev), acpi_pdata->hid)) | 3067 | if (!strcmp(acpi_device_hid(adev), acpi_pdata->hid)) { |
3077 | return &acpi_pdata->pdata; | 3068 | /* |
3069 | * Remove previously installed properties if we | ||
3070 | * are probing this device not for the very first | ||
3071 | * time. | ||
3072 | */ | ||
3073 | device_remove_properties(&client->dev); | ||
3074 | |||
3075 | /* | ||
3076 | * Now install the platform-specific properties | ||
3077 | * that are missing from ACPI. | ||
3078 | */ | ||
3079 | device_add_properties(&client->dev, acpi_pdata->props); | ||
3080 | break; | ||
3081 | } | ||
3078 | 3082 | ||
3079 | acpi_pdata++; | 3083 | acpi_pdata++; |
3080 | } | 3084 | } |
3081 | 3085 | ||
3082 | return ERR_PTR(-ENOENT); | 3086 | return 0; |
3083 | } | 3087 | } |
3084 | #else | 3088 | #else |
3085 | static const struct mxt_platform_data *mxt_parse_acpi(struct i2c_client *client) | 3089 | static int mxt_prepare_acpi_properties(struct i2c_client *client) |
3086 | { | 3090 | { |
3087 | return ERR_PTR(-ENOENT); | 3091 | return -ENOENT; |
3088 | } | 3092 | } |
3089 | #endif | 3093 | #endif |
3090 | 3094 | ||
3091 | static const struct mxt_platform_data * | 3095 | static const struct dmi_system_id chromebook_T9_suspend_dmi[] = { |
3092 | mxt_get_platform_data(struct i2c_client *client) | 3096 | { |
3093 | { | 3097 | .matches = { |
3094 | const struct mxt_platform_data *pdata; | 3098 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), |
3095 | 3099 | DMI_MATCH(DMI_PRODUCT_NAME, "Link"), | |
3096 | pdata = dev_get_platdata(&client->dev); | 3100 | }, |
3097 | if (pdata) | 3101 | }, |
3098 | return pdata; | 3102 | { |
3099 | 3103 | .matches = { | |
3100 | pdata = mxt_parse_dt(client); | 3104 | DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"), |
3101 | if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT) | 3105 | }, |
3102 | return pdata; | 3106 | }, |
3103 | 3107 | { } | |
3104 | pdata = mxt_parse_acpi(client); | 3108 | }; |
3105 | if (!IS_ERR(pdata) || PTR_ERR(pdata) != -ENOENT) | ||
3106 | return pdata; | ||
3107 | |||
3108 | dev_err(&client->dev, "No platform data specified\n"); | ||
3109 | return ERR_PTR(-EINVAL); | ||
3110 | } | ||
3111 | 3109 | ||
3112 | static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) | 3110 | static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) |
3113 | { | 3111 | { |
3114 | struct mxt_data *data; | 3112 | struct mxt_data *data; |
3115 | const struct mxt_platform_data *pdata; | ||
3116 | int error; | 3113 | int error; |
3117 | 3114 | ||
3118 | pdata = mxt_get_platform_data(client); | 3115 | /* |
3119 | if (IS_ERR(pdata)) | 3116 | * Ignore ACPI devices representing bootloader mode. |
3120 | return PTR_ERR(pdata); | 3117 | * |
3118 | * This is a bit of a hack: Google Chromebook BIOS creates ACPI | ||
3119 | * devices for both application and bootloader modes, but we are | ||
3120 | * interested in application mode only (if device is in bootloader | ||
3121 | * mode we'll end up switching into application anyway). So far | ||
3122 | * application mode addresses were all above 0x40, so we'll use it | ||
3123 | * as a threshold. | ||
3124 | */ | ||
3125 | if (ACPI_COMPANION(&client->dev) && client->addr < 0x40) | ||
3126 | return -ENXIO; | ||
3121 | 3127 | ||
3122 | data = devm_kzalloc(&client->dev, sizeof(struct mxt_data), GFP_KERNEL); | 3128 | data = devm_kzalloc(&client->dev, sizeof(struct mxt_data), GFP_KERNEL); |
3123 | if (!data) | 3129 | if (!data) |
@@ -3127,7 +3133,6 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
3127 | client->adapter->nr, client->addr); | 3133 | client->adapter->nr, client->addr); |
3128 | 3134 | ||
3129 | data->client = client; | 3135 | data->client = client; |
3130 | data->pdata = pdata; | ||
3131 | data->irq = client->irq; | 3136 | data->irq = client->irq; |
3132 | i2c_set_clientdata(client, data); | 3137 | i2c_set_clientdata(client, data); |
3133 | 3138 | ||
@@ -3135,6 +3140,17 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
3135 | init_completion(&data->reset_completion); | 3140 | init_completion(&data->reset_completion); |
3136 | init_completion(&data->crc_completion); | 3141 | init_completion(&data->crc_completion); |
3137 | 3142 | ||
3143 | data->suspend_mode = dmi_check_system(chromebook_T9_suspend_dmi) ? | ||
3144 | MXT_SUSPEND_T9_CTRL : MXT_SUSPEND_DEEP_SLEEP; | ||
3145 | |||
3146 | error = mxt_prepare_acpi_properties(client); | ||
3147 | if (error && error != -ENOENT) | ||
3148 | return error; | ||
3149 | |||
3150 | error = mxt_parse_device_properties(data); | ||
3151 | if (error) | ||
3152 | return error; | ||
3153 | |||
3138 | data->reset_gpio = devm_gpiod_get_optional(&client->dev, | 3154 | data->reset_gpio = devm_gpiod_get_optional(&client->dev, |
3139 | "reset", GPIOD_OUT_LOW); | 3155 | "reset", GPIOD_OUT_LOW); |
3140 | if (IS_ERR(data->reset_gpio)) { | 3156 | if (IS_ERR(data->reset_gpio)) { |
@@ -3144,8 +3160,7 @@ static int mxt_probe(struct i2c_client *client, const struct i2c_device_id *id) | |||
3144 | } | 3160 | } |
3145 | 3161 | ||
3146 | error = devm_request_threaded_irq(&client->dev, client->irq, | 3162 | error = devm_request_threaded_irq(&client->dev, client->irq, |
3147 | NULL, mxt_interrupt, | 3163 | NULL, mxt_interrupt, IRQF_ONESHOT, |
3148 | pdata->irqflags | IRQF_ONESHOT, | ||
3149 | client->name, data); | 3164 | client->name, data); |
3150 | if (error) { | 3165 | if (error) { |
3151 | dev_err(&client->dev, "Failed to register interrupt\n"); | 3166 | dev_err(&client->dev, "Failed to register interrupt\n"); |
@@ -3265,7 +3280,7 @@ MODULE_DEVICE_TABLE(i2c, mxt_id); | |||
3265 | static struct i2c_driver mxt_driver = { | 3280 | static struct i2c_driver mxt_driver = { |
3266 | .driver = { | 3281 | .driver = { |
3267 | .name = "atmel_mxt_ts", | 3282 | .name = "atmel_mxt_ts", |
3268 | .of_match_table = of_match_ptr(mxt_of_match), | 3283 | .of_match_table = mxt_of_match, |
3269 | .acpi_match_table = ACPI_PTR(mxt_acpi_id), | 3284 | .acpi_match_table = ACPI_PTR(mxt_acpi_id), |
3270 | .pm = &mxt_pm_ops, | 3285 | .pm = &mxt_pm_ops, |
3271 | }, | 3286 | }, |
diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c index d8599736a41a..5c47f451e43b 100644 --- a/drivers/platform/chrome/chromeos_laptop.c +++ b/drivers/platform/chrome/chromeos_laptop.c | |||
@@ -1,33 +1,20 @@ | |||
1 | /* | 1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | * chromeos_laptop.c - Driver to instantiate Chromebook i2c/smbus devices. | 2 | // Driver to instantiate Chromebook i2c/smbus devices. |
3 | * | 3 | // |
4 | * Author : Benson Leung <bleung@chromium.org> | 4 | // Copyright (C) 2012 Google, Inc. |
5 | * | 5 | // Author: Benson Leung <bleung@chromium.org> |
6 | * Copyright (C) 2012 Google, Inc. | 6 | |
7 | * | 7 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; if not, write to the Free Software | ||
20 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
21 | * | ||
22 | */ | ||
23 | 8 | ||
24 | #include <linux/dmi.h> | 9 | #include <linux/dmi.h> |
25 | #include <linux/i2c.h> | 10 | #include <linux/i2c.h> |
26 | #include <linux/platform_data/atmel_mxt_ts.h> | ||
27 | #include <linux/input.h> | 11 | #include <linux/input.h> |
28 | #include <linux/interrupt.h> | 12 | #include <linux/interrupt.h> |
13 | #include <linux/ioport.h> | ||
29 | #include <linux/module.h> | 14 | #include <linux/module.h> |
15 | #include <linux/pci.h> | ||
30 | #include <linux/platform_device.h> | 16 | #include <linux/platform_device.h> |
17 | #include <linux/property.h> | ||
31 | 18 | ||
32 | #define ATMEL_TP_I2C_ADDR 0x4b | 19 | #define ATMEL_TP_I2C_ADDR 0x4b |
33 | #define ATMEL_TP_I2C_BL_ADDR 0x25 | 20 | #define ATMEL_TP_I2C_BL_ADDR 0x25 |
@@ -38,18 +25,11 @@ | |||
38 | #define ISL_ALS_I2C_ADDR 0x44 | 25 | #define ISL_ALS_I2C_ADDR 0x44 |
39 | #define TAOS_ALS_I2C_ADDR 0x29 | 26 | #define TAOS_ALS_I2C_ADDR 0x29 |
40 | 27 | ||
41 | #define MAX_I2C_DEVICE_DEFERRALS 5 | ||
42 | |||
43 | static struct i2c_client *als; | ||
44 | static struct i2c_client *tp; | ||
45 | static struct i2c_client *ts; | ||
46 | |||
47 | static const char *i2c_adapter_names[] = { | 28 | static const char *i2c_adapter_names[] = { |
48 | "SMBus I801 adapter", | 29 | "SMBus I801 adapter", |
49 | "i915 gmbus vga", | 30 | "i915 gmbus vga", |
50 | "i915 gmbus panel", | 31 | "i915 gmbus panel", |
51 | "Synopsys DesignWare I2C adapter", | 32 | "Synopsys DesignWare I2C adapter", |
52 | "Synopsys DesignWare I2C adapter", | ||
53 | }; | 33 | }; |
54 | 34 | ||
55 | /* Keep this enum consistent with i2c_adapter_names */ | 35 | /* Keep this enum consistent with i2c_adapter_names */ |
@@ -57,126 +37,41 @@ enum i2c_adapter_type { | |||
57 | I2C_ADAPTER_SMBUS = 0, | 37 | I2C_ADAPTER_SMBUS = 0, |
58 | I2C_ADAPTER_VGADDC, | 38 | I2C_ADAPTER_VGADDC, |
59 | I2C_ADAPTER_PANEL, | 39 | I2C_ADAPTER_PANEL, |
60 | I2C_ADAPTER_DESIGNWARE_0, | 40 | I2C_ADAPTER_DESIGNWARE, |
61 | I2C_ADAPTER_DESIGNWARE_1, | ||
62 | }; | ||
63 | |||
64 | enum i2c_peripheral_state { | ||
65 | UNPROBED = 0, | ||
66 | PROBED, | ||
67 | TIMEDOUT, | ||
68 | }; | 41 | }; |
69 | 42 | ||
70 | struct i2c_peripheral { | 43 | struct i2c_peripheral { |
71 | int (*add)(enum i2c_adapter_type type); | 44 | struct i2c_board_info board_info; |
72 | enum i2c_adapter_type type; | 45 | unsigned short alt_addr; |
73 | enum i2c_peripheral_state state; | ||
74 | int tries; | ||
75 | }; | ||
76 | |||
77 | #define MAX_I2C_PERIPHERALS 4 | ||
78 | 46 | ||
79 | struct chromeos_laptop { | 47 | const char *dmi_name; |
80 | struct i2c_peripheral i2c_peripherals[MAX_I2C_PERIPHERALS]; | 48 | unsigned long irqflags; |
81 | }; | 49 | struct resource irq_resource; |
82 | |||
83 | static struct chromeos_laptop *cros_laptop; | ||
84 | |||
85 | static struct i2c_board_info cyapa_device = { | ||
86 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), | ||
87 | .flags = I2C_CLIENT_WAKE, | ||
88 | }; | ||
89 | 50 | ||
90 | static struct i2c_board_info elantech_device = { | 51 | enum i2c_adapter_type type; |
91 | I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR), | 52 | u32 pci_devid; |
92 | .flags = I2C_CLIENT_WAKE, | ||
93 | }; | ||
94 | |||
95 | static struct i2c_board_info isl_als_device = { | ||
96 | I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), | ||
97 | }; | ||
98 | |||
99 | static struct i2c_board_info tsl2583_als_device = { | ||
100 | I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR), | ||
101 | }; | ||
102 | |||
103 | static struct i2c_board_info tsl2563_als_device = { | ||
104 | I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR), | ||
105 | }; | ||
106 | |||
107 | static int mxt_t19_keys[] = { | ||
108 | KEY_RESERVED, | ||
109 | KEY_RESERVED, | ||
110 | KEY_RESERVED, | ||
111 | KEY_RESERVED, | ||
112 | KEY_RESERVED, | ||
113 | BTN_LEFT | ||
114 | }; | ||
115 | |||
116 | static struct mxt_platform_data atmel_224s_tp_platform_data = { | ||
117 | .irqflags = IRQF_TRIGGER_FALLING, | ||
118 | .t19_num_keys = ARRAY_SIZE(mxt_t19_keys), | ||
119 | .t19_keymap = mxt_t19_keys, | ||
120 | .suspend_mode = MXT_SUSPEND_T9_CTRL, | ||
121 | }; | ||
122 | 53 | ||
123 | static struct i2c_board_info atmel_224s_tp_device = { | 54 | struct i2c_client *client; |
124 | I2C_BOARD_INFO("atmel_mxt_tp", ATMEL_TP_I2C_ADDR), | ||
125 | .platform_data = &atmel_224s_tp_platform_data, | ||
126 | .flags = I2C_CLIENT_WAKE, | ||
127 | }; | 55 | }; |
128 | 56 | ||
129 | static struct mxt_platform_data atmel_1664s_platform_data = { | 57 | struct chromeos_laptop { |
130 | .irqflags = IRQF_TRIGGER_FALLING, | 58 | /* |
131 | .suspend_mode = MXT_SUSPEND_T9_CTRL, | 59 | * Note that we can't mark this pointer as const because |
60 | * i2c_new_probed_device() changes passed in I2C board info, so. | ||
61 | */ | ||
62 | struct i2c_peripheral *i2c_peripherals; | ||
63 | unsigned int num_i2c_peripherals; | ||
132 | }; | 64 | }; |
133 | 65 | ||
134 | static struct i2c_board_info atmel_1664s_device = { | 66 | static const struct chromeos_laptop *cros_laptop; |
135 | I2C_BOARD_INFO("atmel_mxt_ts", ATMEL_TS_I2C_ADDR), | ||
136 | .platform_data = &atmel_1664s_platform_data, | ||
137 | .flags = I2C_CLIENT_WAKE, | ||
138 | }; | ||
139 | 67 | ||
140 | static struct i2c_client *__add_probed_i2c_device( | 68 | static struct i2c_client * |
141 | const char *name, | 69 | chromes_laptop_instantiate_i2c_device(struct i2c_adapter *adapter, |
142 | int bus, | 70 | struct i2c_board_info *info, |
143 | struct i2c_board_info *info, | 71 | unsigned short alt_addr) |
144 | const unsigned short *alt_addr_list) | ||
145 | { | 72 | { |
146 | const struct dmi_device *dmi_dev; | ||
147 | const struct dmi_dev_onboard *dev_data; | ||
148 | struct i2c_adapter *adapter; | ||
149 | struct i2c_client *client = NULL; | ||
150 | const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END }; | 73 | const unsigned short addr_list[] = { info->addr, I2C_CLIENT_END }; |
151 | 74 | struct i2c_client *client; | |
152 | if (bus < 0) | ||
153 | return NULL; | ||
154 | /* | ||
155 | * If a name is specified, look for irq platform information stashed | ||
156 | * in DMI_DEV_TYPE_DEV_ONBOARD by the Chrome OS custom system firmware. | ||
157 | */ | ||
158 | if (name) { | ||
159 | dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, name, NULL); | ||
160 | if (!dmi_dev) { | ||
161 | pr_err("%s failed to dmi find device %s.\n", | ||
162 | __func__, | ||
163 | name); | ||
164 | return NULL; | ||
165 | } | ||
166 | dev_data = (struct dmi_dev_onboard *)dmi_dev->device_data; | ||
167 | if (!dev_data) { | ||
168 | pr_err("%s failed to get data from dmi for %s.\n", | ||
169 | __func__, name); | ||
170 | return NULL; | ||
171 | } | ||
172 | info->irq = dev_data->instance; | ||
173 | } | ||
174 | |||
175 | adapter = i2c_get_adapter(bus); | ||
176 | if (!adapter) { | ||
177 | pr_err("%s failed to get i2c adapter %d.\n", __func__, bus); | ||
178 | return NULL; | ||
179 | } | ||
180 | 75 | ||
181 | /* | 76 | /* |
182 | * Add the i2c device. If we can't detect it at the primary | 77 | * Add the i2c device. If we can't detect it at the primary |
@@ -184,339 +79,345 @@ static struct i2c_client *__add_probed_i2c_device( | |||
184 | * structure gets assigned primary address. | 79 | * structure gets assigned primary address. |
185 | */ | 80 | */ |
186 | client = i2c_new_probed_device(adapter, info, addr_list, NULL); | 81 | client = i2c_new_probed_device(adapter, info, addr_list, NULL); |
187 | if (!client && alt_addr_list) { | 82 | if (!client && alt_addr) { |
188 | struct i2c_board_info dummy_info = { | 83 | struct i2c_board_info dummy_info = { |
189 | I2C_BOARD_INFO("dummy", info->addr), | 84 | I2C_BOARD_INFO("dummy", info->addr), |
190 | }; | 85 | }; |
86 | const unsigned short alt_addr_list[] = { | ||
87 | alt_addr, I2C_CLIENT_END | ||
88 | }; | ||
191 | struct i2c_client *dummy; | 89 | struct i2c_client *dummy; |
192 | 90 | ||
193 | dummy = i2c_new_probed_device(adapter, &dummy_info, | 91 | dummy = i2c_new_probed_device(adapter, &dummy_info, |
194 | alt_addr_list, NULL); | 92 | alt_addr_list, NULL); |
195 | if (dummy) { | 93 | if (dummy) { |
196 | pr_debug("%s %d-%02x is probed at %02x\n", | 94 | pr_debug("%d-%02x is probed at %02x\n", |
197 | __func__, bus, info->addr, dummy->addr); | 95 | adapter->nr, info->addr, dummy->addr); |
198 | i2c_unregister_device(dummy); | 96 | i2c_unregister_device(dummy); |
199 | client = i2c_new_device(adapter, info); | 97 | client = i2c_new_device(adapter, info); |
200 | } | 98 | } |
201 | } | 99 | } |
202 | 100 | ||
203 | if (!client) | 101 | if (!client) |
204 | pr_notice("%s failed to register device %d-%02x\n", | 102 | pr_debug("failed to register device %d-%02x\n", |
205 | __func__, bus, info->addr); | 103 | adapter->nr, info->addr); |
206 | else | 104 | else |
207 | pr_debug("%s added i2c device %d-%02x\n", | 105 | pr_debug("added i2c device %d-%02x\n", |
208 | __func__, bus, info->addr); | 106 | adapter->nr, info->addr); |
209 | 107 | ||
210 | i2c_put_adapter(adapter); | ||
211 | return client; | 108 | return client; |
212 | } | 109 | } |
213 | 110 | ||
214 | struct i2c_lookup { | 111 | static bool chromeos_laptop_match_adapter_devid(struct device *dev, u32 devid) |
215 | const char *name; | ||
216 | int instance; | ||
217 | int n; | ||
218 | }; | ||
219 | |||
220 | static int __find_i2c_adap(struct device *dev, void *data) | ||
221 | { | ||
222 | struct i2c_lookup *lookup = data; | ||
223 | static const char *prefix = "i2c-"; | ||
224 | struct i2c_adapter *adapter; | ||
225 | |||
226 | if (strncmp(dev_name(dev), prefix, strlen(prefix)) != 0) | ||
227 | return 0; | ||
228 | adapter = to_i2c_adapter(dev); | ||
229 | if (strncmp(adapter->name, lookup->name, strlen(lookup->name)) == 0 && | ||
230 | lookup->n++ == lookup->instance) | ||
231 | return 1; | ||
232 | return 0; | ||
233 | } | ||
234 | |||
235 | static int find_i2c_adapter_num(enum i2c_adapter_type type) | ||
236 | { | ||
237 | struct device *dev = NULL; | ||
238 | struct i2c_adapter *adapter; | ||
239 | struct i2c_lookup lookup; | ||
240 | |||
241 | memset(&lookup, 0, sizeof(lookup)); | ||
242 | lookup.name = i2c_adapter_names[type]; | ||
243 | lookup.instance = (type == I2C_ADAPTER_DESIGNWARE_1) ? 1 : 0; | ||
244 | |||
245 | /* find the adapter by name */ | ||
246 | dev = bus_find_device(&i2c_bus_type, NULL, &lookup, __find_i2c_adap); | ||
247 | if (!dev) { | ||
248 | /* Adapters may appear later. Deferred probing will retry */ | ||
249 | pr_notice("%s: i2c adapter %s not found on system.\n", __func__, | ||
250 | lookup.name); | ||
251 | return -ENODEV; | ||
252 | } | ||
253 | adapter = to_i2c_adapter(dev); | ||
254 | return adapter->nr; | ||
255 | } | ||
256 | |||
257 | /* | ||
258 | * Takes a list of addresses in addrs as such : | ||
259 | * { addr1, ... , addrn, I2C_CLIENT_END }; | ||
260 | * add_probed_i2c_device will use i2c_new_probed_device | ||
261 | * and probe for devices at all of the addresses listed. | ||
262 | * Returns NULL if no devices found. | ||
263 | * See Documentation/i2c/instantiating-devices for more information. | ||
264 | */ | ||
265 | static struct i2c_client *add_probed_i2c_device( | ||
266 | const char *name, | ||
267 | enum i2c_adapter_type type, | ||
268 | struct i2c_board_info *info, | ||
269 | const unsigned short *addrs) | ||
270 | { | 112 | { |
271 | return __add_probed_i2c_device(name, | 113 | struct pci_dev *pdev; |
272 | find_i2c_adapter_num(type), | ||
273 | info, | ||
274 | addrs); | ||
275 | } | ||
276 | 114 | ||
277 | /* | 115 | if (!dev_is_pci(dev)) |
278 | * Probes for a device at a single address, the one provided by | 116 | return false; |
279 | * info->addr. | ||
280 | * Returns NULL if no device found. | ||
281 | */ | ||
282 | static struct i2c_client *add_i2c_device(const char *name, | ||
283 | enum i2c_adapter_type type, | ||
284 | struct i2c_board_info *info) | ||
285 | { | ||
286 | return __add_probed_i2c_device(name, | ||
287 | find_i2c_adapter_num(type), | ||
288 | info, | ||
289 | NULL); | ||
290 | } | ||
291 | |||
292 | static int setup_cyapa_tp(enum i2c_adapter_type type) | ||
293 | { | ||
294 | if (tp) | ||
295 | return 0; | ||
296 | 117 | ||
297 | /* add cyapa touchpad */ | 118 | pdev = to_pci_dev(dev); |
298 | tp = add_i2c_device("trackpad", type, &cyapa_device); | 119 | return devid == PCI_DEVID(pdev->bus->number, pdev->devfn); |
299 | return (!tp) ? -EAGAIN : 0; | ||
300 | } | 120 | } |
301 | 121 | ||
302 | static int setup_atmel_224s_tp(enum i2c_adapter_type type) | 122 | static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter) |
303 | { | 123 | { |
304 | const unsigned short addr_list[] = { ATMEL_TP_I2C_BL_ADDR, | 124 | struct i2c_peripheral *i2c_dev; |
305 | I2C_CLIENT_END }; | 125 | int i; |
306 | if (tp) | ||
307 | return 0; | ||
308 | |||
309 | /* add atmel mxt touchpad */ | ||
310 | tp = add_probed_i2c_device("trackpad", type, | ||
311 | &atmel_224s_tp_device, addr_list); | ||
312 | return (!tp) ? -EAGAIN : 0; | ||
313 | } | ||
314 | 126 | ||
315 | static int setup_elantech_tp(enum i2c_adapter_type type) | 127 | for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) { |
316 | { | 128 | i2c_dev = &cros_laptop->i2c_peripherals[i]; |
317 | if (tp) | ||
318 | return 0; | ||
319 | 129 | ||
320 | /* add elantech touchpad */ | 130 | /* Skip devices already created */ |
321 | tp = add_i2c_device("trackpad", type, &elantech_device); | 131 | if (i2c_dev->client) |
322 | return (!tp) ? -EAGAIN : 0; | 132 | continue; |
323 | } | ||
324 | 133 | ||
325 | static int setup_atmel_1664s_ts(enum i2c_adapter_type type) | 134 | if (strncmp(adapter->name, i2c_adapter_names[i2c_dev->type], |
326 | { | 135 | strlen(i2c_adapter_names[i2c_dev->type]))) |
327 | const unsigned short addr_list[] = { ATMEL_TS_I2C_BL_ADDR, | 136 | continue; |
328 | I2C_CLIENT_END }; | ||
329 | if (ts) | ||
330 | return 0; | ||
331 | |||
332 | /* add atmel mxt touch device */ | ||
333 | ts = add_probed_i2c_device("touchscreen", type, | ||
334 | &atmel_1664s_device, addr_list); | ||
335 | return (!ts) ? -EAGAIN : 0; | ||
336 | } | ||
337 | 137 | ||
338 | static int setup_isl29018_als(enum i2c_adapter_type type) | 138 | if (i2c_dev->pci_devid && |
339 | { | 139 | !chromeos_laptop_match_adapter_devid(adapter->dev.parent, |
340 | if (als) | 140 | i2c_dev->pci_devid)) { |
341 | return 0; | 141 | continue; |
142 | } | ||
342 | 143 | ||
343 | /* add isl29018 light sensor */ | 144 | i2c_dev->client = |
344 | als = add_i2c_device("lightsensor", type, &isl_als_device); | 145 | chromes_laptop_instantiate_i2c_device(adapter, |
345 | return (!als) ? -EAGAIN : 0; | 146 | &i2c_dev->board_info, |
147 | i2c_dev->alt_addr); | ||
148 | } | ||
346 | } | 149 | } |
347 | 150 | ||
348 | static int setup_tsl2583_als(enum i2c_adapter_type type) | 151 | static void chromeos_laptop_detach_i2c_client(struct i2c_client *client) |
349 | { | 152 | { |
350 | if (als) | 153 | struct i2c_peripheral *i2c_dev; |
351 | return 0; | 154 | int i; |
352 | |||
353 | /* add tsl2583 light sensor */ | ||
354 | als = add_i2c_device(NULL, type, &tsl2583_als_device); | ||
355 | return (!als) ? -EAGAIN : 0; | ||
356 | } | ||
357 | 155 | ||
358 | static int setup_tsl2563_als(enum i2c_adapter_type type) | 156 | for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) { |
359 | { | 157 | i2c_dev = &cros_laptop->i2c_peripherals[i]; |
360 | if (als) | ||
361 | return 0; | ||
362 | 158 | ||
363 | /* add tsl2563 light sensor */ | 159 | if (i2c_dev->client == client) |
364 | als = add_i2c_device(NULL, type, &tsl2563_als_device); | 160 | i2c_dev->client = NULL; |
365 | return (!als) ? -EAGAIN : 0; | 161 | } |
366 | } | 162 | } |
367 | 163 | ||
368 | static int __init chromeos_laptop_dmi_matched(const struct dmi_system_id *id) | 164 | static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb, |
165 | unsigned long action, void *data) | ||
369 | { | 166 | { |
370 | cros_laptop = (void *)id->driver_data; | 167 | struct device *dev = data; |
371 | pr_debug("DMI Matched %s.\n", id->ident); | 168 | |
169 | switch (action) { | ||
170 | case BUS_NOTIFY_ADD_DEVICE: | ||
171 | if (dev->type == &i2c_adapter_type) | ||
172 | chromeos_laptop_check_adapter(to_i2c_adapter(dev)); | ||
173 | break; | ||
174 | |||
175 | case BUS_NOTIFY_REMOVED_DEVICE: | ||
176 | if (dev->type == &i2c_client_type) | ||
177 | chromeos_laptop_detach_i2c_client(to_i2c_client(dev)); | ||
178 | break; | ||
179 | } | ||
372 | 180 | ||
373 | /* Indicate to dmi_scan that processing is done. */ | 181 | return 0; |
374 | return 1; | ||
375 | } | 182 | } |
376 | 183 | ||
377 | static int chromeos_laptop_probe(struct platform_device *pdev) | 184 | static struct notifier_block chromeos_laptop_i2c_notifier = { |
378 | { | 185 | .notifier_call = chromeos_laptop_i2c_notifier_call, |
379 | int i; | 186 | }; |
380 | int ret = 0; | ||
381 | |||
382 | for (i = 0; i < MAX_I2C_PERIPHERALS; i++) { | ||
383 | struct i2c_peripheral *i2c_dev; | ||
384 | |||
385 | i2c_dev = &cros_laptop->i2c_peripherals[i]; | ||
386 | |||
387 | /* No more peripherals. */ | ||
388 | if (i2c_dev->add == NULL) | ||
389 | break; | ||
390 | |||
391 | if (i2c_dev->state == TIMEDOUT || i2c_dev->state == PROBED) | ||
392 | continue; | ||
393 | |||
394 | /* | ||
395 | * Check that the i2c adapter is present. | ||
396 | * -EPROBE_DEFER if missing as the adapter may appear much | ||
397 | * later. | ||
398 | */ | ||
399 | if (find_i2c_adapter_num(i2c_dev->type) == -ENODEV) { | ||
400 | ret = -EPROBE_DEFER; | ||
401 | continue; | ||
402 | } | ||
403 | |||
404 | /* Add the device. */ | ||
405 | if (i2c_dev->add(i2c_dev->type) == -EAGAIN) { | ||
406 | /* | ||
407 | * Set -EPROBE_DEFER a limited num of times | ||
408 | * if device is not successfully added. | ||
409 | */ | ||
410 | if (++i2c_dev->tries < MAX_I2C_DEVICE_DEFERRALS) { | ||
411 | ret = -EPROBE_DEFER; | ||
412 | } else { | ||
413 | /* Ran out of tries. */ | ||
414 | pr_notice("%s: Ran out of tries for device.\n", | ||
415 | __func__); | ||
416 | i2c_dev->state = TIMEDOUT; | ||
417 | } | ||
418 | } else { | ||
419 | i2c_dev->state = PROBED; | ||
420 | } | ||
421 | } | ||
422 | 187 | ||
423 | return ret; | 188 | #define DECLARE_CROS_LAPTOP(_name) \ |
189 | static const struct chromeos_laptop _name __initconst = { \ | ||
190 | .i2c_peripherals = _name##_peripherals, \ | ||
191 | .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \ | ||
424 | } | 192 | } |
425 | 193 | ||
426 | static struct chromeos_laptop samsung_series_5_550 = { | 194 | static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = { |
427 | .i2c_peripherals = { | 195 | /* Touchpad. */ |
428 | /* Touchpad. */ | 196 | { |
429 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, | 197 | .board_info = { |
430 | /* Light Sensor. */ | 198 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), |
431 | { .add = setup_isl29018_als, I2C_ADAPTER_SMBUS }, | 199 | .flags = I2C_CLIENT_WAKE, |
200 | }, | ||
201 | .dmi_name = "trackpad", | ||
202 | .type = I2C_ADAPTER_SMBUS, | ||
203 | }, | ||
204 | /* Light Sensor. */ | ||
205 | { | ||
206 | .board_info = { | ||
207 | I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), | ||
208 | }, | ||
209 | .dmi_name = "lightsensor", | ||
210 | .type = I2C_ADAPTER_SMBUS, | ||
432 | }, | 211 | }, |
433 | }; | 212 | }; |
213 | DECLARE_CROS_LAPTOP(samsung_series_5_550); | ||
434 | 214 | ||
435 | static struct chromeos_laptop samsung_series_5 = { | 215 | static struct i2c_peripheral samsung_series_5_peripherals[] __initdata = { |
436 | .i2c_peripherals = { | 216 | /* Light Sensor. */ |
437 | /* Light Sensor. */ | 217 | { |
438 | { .add = setup_tsl2583_als, I2C_ADAPTER_SMBUS }, | 218 | .board_info = { |
219 | I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR), | ||
220 | }, | ||
221 | .type = I2C_ADAPTER_SMBUS, | ||
439 | }, | 222 | }, |
440 | }; | 223 | }; |
224 | DECLARE_CROS_LAPTOP(samsung_series_5); | ||
441 | 225 | ||
442 | static struct chromeos_laptop chromebook_pixel = { | 226 | static const int chromebook_pixel_tp_keys[] __initconst = { |
443 | .i2c_peripherals = { | 227 | KEY_RESERVED, |
444 | /* Touch Screen. */ | 228 | KEY_RESERVED, |
445 | { .add = setup_atmel_1664s_ts, I2C_ADAPTER_PANEL }, | 229 | KEY_RESERVED, |
446 | /* Touchpad. */ | 230 | KEY_RESERVED, |
447 | { .add = setup_atmel_224s_tp, I2C_ADAPTER_VGADDC }, | 231 | KEY_RESERVED, |
448 | /* Light Sensor. */ | 232 | BTN_LEFT |
449 | { .add = setup_isl29018_als, I2C_ADAPTER_PANEL }, | ||
450 | }, | ||
451 | }; | 233 | }; |
452 | 234 | ||
453 | static struct chromeos_laptop hp_chromebook_14 = { | 235 | static const struct property_entry |
454 | .i2c_peripherals = { | 236 | chromebook_pixel_trackpad_props[] __initconst = { |
455 | /* Touchpad. */ | 237 | PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys), |
456 | { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, | 238 | { } |
239 | }; | ||
240 | |||
241 | static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = { | ||
242 | /* Touch Screen. */ | ||
243 | { | ||
244 | .board_info = { | ||
245 | I2C_BOARD_INFO("atmel_mxt_ts", | ||
246 | ATMEL_TS_I2C_ADDR), | ||
247 | .flags = I2C_CLIENT_WAKE, | ||
248 | }, | ||
249 | .dmi_name = "touchscreen", | ||
250 | .irqflags = IRQF_TRIGGER_FALLING, | ||
251 | .type = I2C_ADAPTER_PANEL, | ||
252 | .alt_addr = ATMEL_TS_I2C_BL_ADDR, | ||
253 | }, | ||
254 | /* Touchpad. */ | ||
255 | { | ||
256 | .board_info = { | ||
257 | I2C_BOARD_INFO("atmel_mxt_tp", | ||
258 | ATMEL_TP_I2C_ADDR), | ||
259 | .properties = | ||
260 | chromebook_pixel_trackpad_props, | ||
261 | .flags = I2C_CLIENT_WAKE, | ||
262 | }, | ||
263 | .dmi_name = "trackpad", | ||
264 | .irqflags = IRQF_TRIGGER_FALLING, | ||
265 | .type = I2C_ADAPTER_VGADDC, | ||
266 | .alt_addr = ATMEL_TP_I2C_BL_ADDR, | ||
267 | }, | ||
268 | /* Light Sensor. */ | ||
269 | { | ||
270 | .board_info = { | ||
271 | I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), | ||
272 | }, | ||
273 | .dmi_name = "lightsensor", | ||
274 | .type = I2C_ADAPTER_PANEL, | ||
457 | }, | 275 | }, |
458 | }; | 276 | }; |
277 | DECLARE_CROS_LAPTOP(chromebook_pixel); | ||
459 | 278 | ||
460 | static struct chromeos_laptop dell_chromebook_11 = { | 279 | static struct i2c_peripheral hp_chromebook_14_peripherals[] __initdata = { |
461 | .i2c_peripherals = { | 280 | /* Touchpad. */ |
462 | /* Touchpad. */ | 281 | { |
463 | { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, | 282 | .board_info = { |
464 | /* Elan Touchpad option. */ | 283 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), |
465 | { .add = setup_elantech_tp, I2C_ADAPTER_DESIGNWARE_0 }, | 284 | .flags = I2C_CLIENT_WAKE, |
285 | }, | ||
286 | .dmi_name = "trackpad", | ||
287 | .type = I2C_ADAPTER_DESIGNWARE, | ||
466 | }, | 288 | }, |
467 | }; | 289 | }; |
290 | DECLARE_CROS_LAPTOP(hp_chromebook_14); | ||
468 | 291 | ||
469 | static struct chromeos_laptop toshiba_cb35 = { | 292 | static struct i2c_peripheral dell_chromebook_11_peripherals[] __initdata = { |
470 | .i2c_peripherals = { | 293 | /* Touchpad. */ |
471 | /* Touchpad. */ | 294 | { |
472 | { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, | 295 | .board_info = { |
296 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), | ||
297 | .flags = I2C_CLIENT_WAKE, | ||
298 | }, | ||
299 | .dmi_name = "trackpad", | ||
300 | .type = I2C_ADAPTER_DESIGNWARE, | ||
301 | }, | ||
302 | /* Elan Touchpad option. */ | ||
303 | { | ||
304 | .board_info = { | ||
305 | I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR), | ||
306 | .flags = I2C_CLIENT_WAKE, | ||
307 | }, | ||
308 | .dmi_name = "trackpad", | ||
309 | .type = I2C_ADAPTER_DESIGNWARE, | ||
473 | }, | 310 | }, |
474 | }; | 311 | }; |
312 | DECLARE_CROS_LAPTOP(dell_chromebook_11); | ||
475 | 313 | ||
476 | static struct chromeos_laptop acer_c7_chromebook = { | 314 | static struct i2c_peripheral toshiba_cb35_peripherals[] __initdata = { |
477 | .i2c_peripherals = { | 315 | /* Touchpad. */ |
478 | /* Touchpad. */ | 316 | { |
479 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, | 317 | .board_info = { |
318 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), | ||
319 | .flags = I2C_CLIENT_WAKE, | ||
320 | }, | ||
321 | .dmi_name = "trackpad", | ||
322 | .type = I2C_ADAPTER_DESIGNWARE, | ||
480 | }, | 323 | }, |
481 | }; | 324 | }; |
325 | DECLARE_CROS_LAPTOP(toshiba_cb35); | ||
482 | 326 | ||
483 | static struct chromeos_laptop acer_ac700 = { | 327 | static struct i2c_peripheral acer_c7_chromebook_peripherals[] __initdata = { |
484 | .i2c_peripherals = { | 328 | /* Touchpad. */ |
485 | /* Light Sensor. */ | 329 | { |
486 | { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, | 330 | .board_info = { |
331 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), | ||
332 | .flags = I2C_CLIENT_WAKE, | ||
333 | }, | ||
334 | .dmi_name = "trackpad", | ||
335 | .type = I2C_ADAPTER_SMBUS, | ||
487 | }, | 336 | }, |
488 | }; | 337 | }; |
338 | DECLARE_CROS_LAPTOP(acer_c7_chromebook); | ||
489 | 339 | ||
490 | static struct chromeos_laptop acer_c720 = { | 340 | static struct i2c_peripheral acer_ac700_peripherals[] __initdata = { |
491 | .i2c_peripherals = { | 341 | /* Light Sensor. */ |
492 | /* Touchscreen. */ | 342 | { |
493 | { .add = setup_atmel_1664s_ts, I2C_ADAPTER_DESIGNWARE_1 }, | 343 | .board_info = { |
494 | /* Touchpad. */ | 344 | I2C_BOARD_INFO("tsl2583", TAOS_ALS_I2C_ADDR), |
495 | { .add = setup_cyapa_tp, I2C_ADAPTER_DESIGNWARE_0 }, | 345 | }, |
496 | /* Elan Touchpad option. */ | 346 | .type = I2C_ADAPTER_SMBUS, |
497 | { .add = setup_elantech_tp, I2C_ADAPTER_DESIGNWARE_0 }, | ||
498 | /* Light Sensor. */ | ||
499 | { .add = setup_isl29018_als, I2C_ADAPTER_DESIGNWARE_1 }, | ||
500 | }, | 347 | }, |
501 | }; | 348 | }; |
349 | DECLARE_CROS_LAPTOP(acer_ac700); | ||
502 | 350 | ||
503 | static struct chromeos_laptop hp_pavilion_14_chromebook = { | 351 | static struct i2c_peripheral acer_c720_peripherals[] __initdata = { |
504 | .i2c_peripherals = { | 352 | /* Touchscreen. */ |
505 | /* Touchpad. */ | 353 | { |
506 | { .add = setup_cyapa_tp, I2C_ADAPTER_SMBUS }, | 354 | .board_info = { |
355 | I2C_BOARD_INFO("atmel_mxt_ts", | ||
356 | ATMEL_TS_I2C_ADDR), | ||
357 | .flags = I2C_CLIENT_WAKE, | ||
358 | }, | ||
359 | .dmi_name = "touchscreen", | ||
360 | .irqflags = IRQF_TRIGGER_FALLING, | ||
361 | .type = I2C_ADAPTER_DESIGNWARE, | ||
362 | .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)), | ||
363 | .alt_addr = ATMEL_TS_I2C_BL_ADDR, | ||
364 | }, | ||
365 | /* Touchpad. */ | ||
366 | { | ||
367 | .board_info = { | ||
368 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), | ||
369 | .flags = I2C_CLIENT_WAKE, | ||
370 | }, | ||
371 | .dmi_name = "trackpad", | ||
372 | .type = I2C_ADAPTER_DESIGNWARE, | ||
373 | .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)), | ||
374 | }, | ||
375 | /* Elan Touchpad option. */ | ||
376 | { | ||
377 | .board_info = { | ||
378 | I2C_BOARD_INFO("elan_i2c", ELAN_TP_I2C_ADDR), | ||
379 | .flags = I2C_CLIENT_WAKE, | ||
380 | }, | ||
381 | .dmi_name = "trackpad", | ||
382 | .type = I2C_ADAPTER_DESIGNWARE, | ||
383 | .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x1)), | ||
384 | }, | ||
385 | /* Light Sensor. */ | ||
386 | { | ||
387 | .board_info = { | ||
388 | I2C_BOARD_INFO("isl29018", ISL_ALS_I2C_ADDR), | ||
389 | }, | ||
390 | .dmi_name = "lightsensor", | ||
391 | .type = I2C_ADAPTER_DESIGNWARE, | ||
392 | .pci_devid = PCI_DEVID(0, PCI_DEVFN(0x15, 0x2)), | ||
507 | }, | 393 | }, |
508 | }; | 394 | }; |
395 | DECLARE_CROS_LAPTOP(acer_c720); | ||
509 | 396 | ||
510 | static struct chromeos_laptop cr48 = { | 397 | static struct i2c_peripheral |
511 | .i2c_peripherals = { | 398 | hp_pavilion_14_chromebook_peripherals[] __initdata = { |
512 | /* Light Sensor. */ | 399 | /* Touchpad. */ |
513 | { .add = setup_tsl2563_als, I2C_ADAPTER_SMBUS }, | 400 | { |
401 | .board_info = { | ||
402 | I2C_BOARD_INFO("cyapa", CYAPA_TP_I2C_ADDR), | ||
403 | .flags = I2C_CLIENT_WAKE, | ||
404 | }, | ||
405 | .dmi_name = "trackpad", | ||
406 | .type = I2C_ADAPTER_SMBUS, | ||
514 | }, | 407 | }, |
515 | }; | 408 | }; |
409 | DECLARE_CROS_LAPTOP(hp_pavilion_14_chromebook); | ||
516 | 410 | ||
517 | #define _CBDD(board_) \ | 411 | static struct i2c_peripheral cr48_peripherals[] __initdata = { |
518 | .callback = chromeos_laptop_dmi_matched, \ | 412 | /* Light Sensor. */ |
519 | .driver_data = (void *)&board_ | 413 | { |
414 | .board_info = { | ||
415 | I2C_BOARD_INFO("tsl2563", TAOS_ALS_I2C_ADDR), | ||
416 | }, | ||
417 | .type = I2C_ADAPTER_SMBUS, | ||
418 | }, | ||
419 | }; | ||
420 | DECLARE_CROS_LAPTOP(cr48); | ||
520 | 421 | ||
521 | static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { | 422 | static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { |
522 | { | 423 | { |
@@ -525,14 +426,14 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { | |||
525 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"), | 426 | DMI_MATCH(DMI_SYS_VENDOR, "SAMSUNG"), |
526 | DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"), | 427 | DMI_MATCH(DMI_PRODUCT_NAME, "Lumpy"), |
527 | }, | 428 | }, |
528 | _CBDD(samsung_series_5_550), | 429 | .driver_data = (void *)&samsung_series_5_550, |
529 | }, | 430 | }, |
530 | { | 431 | { |
531 | .ident = "Samsung Series 5", | 432 | .ident = "Samsung Series 5", |
532 | .matches = { | 433 | .matches = { |
533 | DMI_MATCH(DMI_PRODUCT_NAME, "Alex"), | 434 | DMI_MATCH(DMI_PRODUCT_NAME, "Alex"), |
534 | }, | 435 | }, |
535 | _CBDD(samsung_series_5), | 436 | .driver_data = (void *)&samsung_series_5, |
536 | }, | 437 | }, |
537 | { | 438 | { |
538 | .ident = "Chromebook Pixel", | 439 | .ident = "Chromebook Pixel", |
@@ -540,7 +441,7 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { | |||
540 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), | 441 | DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"), |
541 | DMI_MATCH(DMI_PRODUCT_NAME, "Link"), | 442 | DMI_MATCH(DMI_PRODUCT_NAME, "Link"), |
542 | }, | 443 | }, |
543 | _CBDD(chromebook_pixel), | 444 | .driver_data = (void *)&chromebook_pixel, |
544 | }, | 445 | }, |
545 | { | 446 | { |
546 | .ident = "Wolf", | 447 | .ident = "Wolf", |
@@ -548,7 +449,7 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { | |||
548 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), | 449 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), |
549 | DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"), | 450 | DMI_MATCH(DMI_PRODUCT_NAME, "Wolf"), |
550 | }, | 451 | }, |
551 | _CBDD(dell_chromebook_11), | 452 | .driver_data = (void *)&dell_chromebook_11, |
552 | }, | 453 | }, |
553 | { | 454 | { |
554 | .ident = "HP Chromebook 14", | 455 | .ident = "HP Chromebook 14", |
@@ -556,7 +457,7 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { | |||
556 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), | 457 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), |
557 | DMI_MATCH(DMI_PRODUCT_NAME, "Falco"), | 458 | DMI_MATCH(DMI_PRODUCT_NAME, "Falco"), |
558 | }, | 459 | }, |
559 | _CBDD(hp_chromebook_14), | 460 | .driver_data = (void *)&hp_chromebook_14, |
560 | }, | 461 | }, |
561 | { | 462 | { |
562 | .ident = "Toshiba CB35", | 463 | .ident = "Toshiba CB35", |
@@ -564,99 +465,214 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { | |||
564 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), | 465 | DMI_MATCH(DMI_BIOS_VENDOR, "coreboot"), |
565 | DMI_MATCH(DMI_PRODUCT_NAME, "Leon"), | 466 | DMI_MATCH(DMI_PRODUCT_NAME, "Leon"), |
566 | }, | 467 | }, |
567 | _CBDD(toshiba_cb35), | 468 | .driver_data = (void *)&toshiba_cb35, |
568 | }, | 469 | }, |
569 | { | 470 | { |
570 | .ident = "Acer C7 Chromebook", | 471 | .ident = "Acer C7 Chromebook", |
571 | .matches = { | 472 | .matches = { |
572 | DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"), | 473 | DMI_MATCH(DMI_PRODUCT_NAME, "Parrot"), |
573 | }, | 474 | }, |
574 | _CBDD(acer_c7_chromebook), | 475 | .driver_data = (void *)&acer_c7_chromebook, |
575 | }, | 476 | }, |
576 | { | 477 | { |
577 | .ident = "Acer AC700", | 478 | .ident = "Acer AC700", |
578 | .matches = { | 479 | .matches = { |
579 | DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), | 480 | DMI_MATCH(DMI_PRODUCT_NAME, "ZGB"), |
580 | }, | 481 | }, |
581 | _CBDD(acer_ac700), | 482 | .driver_data = (void *)&acer_ac700, |
582 | }, | 483 | }, |
583 | { | 484 | { |
584 | .ident = "Acer C720", | 485 | .ident = "Acer C720", |
585 | .matches = { | 486 | .matches = { |
586 | DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"), | 487 | DMI_MATCH(DMI_PRODUCT_NAME, "Peppy"), |
587 | }, | 488 | }, |
588 | _CBDD(acer_c720), | 489 | .driver_data = (void *)&acer_c720, |
589 | }, | 490 | }, |
590 | { | 491 | { |
591 | .ident = "HP Pavilion 14 Chromebook", | 492 | .ident = "HP Pavilion 14 Chromebook", |
592 | .matches = { | 493 | .matches = { |
593 | DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"), | 494 | DMI_MATCH(DMI_PRODUCT_NAME, "Butterfly"), |
594 | }, | 495 | }, |
595 | _CBDD(hp_pavilion_14_chromebook), | 496 | .driver_data = (void *)&hp_pavilion_14_chromebook, |
596 | }, | 497 | }, |
597 | { | 498 | { |
598 | .ident = "Cr-48", | 499 | .ident = "Cr-48", |
599 | .matches = { | 500 | .matches = { |
600 | DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), | 501 | DMI_MATCH(DMI_PRODUCT_NAME, "Mario"), |
601 | }, | 502 | }, |
602 | _CBDD(cr48), | 503 | .driver_data = (void *)&cr48, |
603 | }, | 504 | }, |
604 | { } | 505 | { } |
605 | }; | 506 | }; |
606 | MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); | 507 | MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); |
607 | 508 | ||
608 | static struct platform_device *cros_platform_device; | 509 | static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data) |
510 | { | ||
511 | struct i2c_adapter *adapter; | ||
609 | 512 | ||
610 | static struct platform_driver cros_platform_driver = { | 513 | adapter = i2c_verify_adapter(dev); |
611 | .driver = { | 514 | if (adapter) |
612 | .name = "chromeos_laptop", | 515 | chromeos_laptop_check_adapter(adapter); |
613 | }, | 516 | |
614 | .probe = chromeos_laptop_probe, | 517 | return 0; |
615 | }; | 518 | } |
519 | |||
520 | static int __init chromeos_laptop_get_irq_from_dmi(const char *dmi_name) | ||
521 | { | ||
522 | const struct dmi_device *dmi_dev; | ||
523 | const struct dmi_dev_onboard *dev_data; | ||
524 | |||
525 | dmi_dev = dmi_find_device(DMI_DEV_TYPE_DEV_ONBOARD, dmi_name, NULL); | ||
526 | if (!dmi_dev) { | ||
527 | pr_err("failed to find DMI device '%s'\n", dmi_name); | ||
528 | return -ENOENT; | ||
529 | } | ||
530 | |||
531 | dev_data = dmi_dev->device_data; | ||
532 | if (!dev_data) { | ||
533 | pr_err("failed to get data from DMI for '%s'\n", dmi_name); | ||
534 | return -EINVAL; | ||
535 | } | ||
536 | |||
537 | return dev_data->instance; | ||
538 | } | ||
539 | |||
540 | static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev) | ||
541 | { | ||
542 | int irq; | ||
543 | |||
544 | if (i2c_dev->dmi_name) { | ||
545 | irq = chromeos_laptop_get_irq_from_dmi(i2c_dev->dmi_name); | ||
546 | if (irq < 0) | ||
547 | return irq; | ||
548 | |||
549 | i2c_dev->irq_resource = (struct resource) | ||
550 | DEFINE_RES_NAMED(irq, 1, NULL, | ||
551 | IORESOURCE_IRQ | i2c_dev->irqflags); | ||
552 | i2c_dev->board_info.resources = &i2c_dev->irq_resource; | ||
553 | i2c_dev->board_info.num_resources = 1; | ||
554 | } | ||
555 | |||
556 | return 0; | ||
557 | } | ||
558 | |||
559 | static struct chromeos_laptop * __init | ||
560 | chromeos_laptop_prepare(const struct chromeos_laptop *src) | ||
561 | { | ||
562 | struct chromeos_laptop *cros_laptop; | ||
563 | struct i2c_peripheral *i2c_dev; | ||
564 | struct i2c_board_info *info; | ||
565 | int error; | ||
566 | int i; | ||
567 | |||
568 | cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL); | ||
569 | if (!cros_laptop) | ||
570 | return ERR_PTR(-ENOMEM); | ||
571 | |||
572 | cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals, | ||
573 | src->num_i2c_peripherals * | ||
574 | sizeof(*src->i2c_peripherals), | ||
575 | GFP_KERNEL); | ||
576 | if (!cros_laptop->i2c_peripherals) { | ||
577 | error = -ENOMEM; | ||
578 | goto err_free_cros_laptop; | ||
579 | } | ||
580 | |||
581 | cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals; | ||
582 | |||
583 | for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) { | ||
584 | i2c_dev = &cros_laptop->i2c_peripherals[i]; | ||
585 | info = &i2c_dev->board_info; | ||
586 | |||
587 | error = chromeos_laptop_setup_irq(i2c_dev); | ||
588 | if (error) | ||
589 | goto err_destroy_cros_peripherals; | ||
590 | |||
591 | /* We need to deep-copy properties */ | ||
592 | if (info->properties) { | ||
593 | info->properties = | ||
594 | property_entries_dup(info->properties); | ||
595 | if (IS_ERR(info->properties)) { | ||
596 | error = PTR_ERR(info->properties); | ||
597 | goto err_destroy_cros_peripherals; | ||
598 | } | ||
599 | } | ||
600 | } | ||
601 | |||
602 | return cros_laptop; | ||
603 | |||
604 | err_destroy_cros_peripherals: | ||
605 | while (--i >= 0) { | ||
606 | i2c_dev = &cros_laptop->i2c_peripherals[i]; | ||
607 | info = &i2c_dev->board_info; | ||
608 | if (info->properties) | ||
609 | property_entries_free(info->properties); | ||
610 | } | ||
611 | kfree(cros_laptop->i2c_peripherals); | ||
612 | err_free_cros_laptop: | ||
613 | kfree(cros_laptop); | ||
614 | return ERR_PTR(error); | ||
615 | } | ||
616 | |||
617 | static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop) | ||
618 | { | ||
619 | struct i2c_peripheral *i2c_dev; | ||
620 | struct i2c_board_info *info; | ||
621 | int i; | ||
622 | |||
623 | for (i = 0; i < cros_laptop->num_i2c_peripherals; i++) { | ||
624 | i2c_dev = &cros_laptop->i2c_peripherals[i]; | ||
625 | info = &i2c_dev->board_info; | ||
626 | |||
627 | if (i2c_dev->client) | ||
628 | i2c_unregister_device(i2c_dev->client); | ||
629 | |||
630 | if (info->properties) | ||
631 | property_entries_free(info->properties); | ||
632 | } | ||
633 | |||
634 | kfree(cros_laptop->i2c_peripherals); | ||
635 | kfree(cros_laptop); | ||
636 | } | ||
616 | 637 | ||
617 | static int __init chromeos_laptop_init(void) | 638 | static int __init chromeos_laptop_init(void) |
618 | { | 639 | { |
619 | int ret; | 640 | const struct dmi_system_id *dmi_id; |
641 | int error; | ||
620 | 642 | ||
621 | if (!dmi_check_system(chromeos_laptop_dmi_table)) { | 643 | dmi_id = dmi_first_match(chromeos_laptop_dmi_table); |
622 | pr_debug("%s unsupported system.\n", __func__); | 644 | if (!dmi_id) { |
645 | pr_debug("unsupported system\n"); | ||
623 | return -ENODEV; | 646 | return -ENODEV; |
624 | } | 647 | } |
625 | 648 | ||
626 | ret = platform_driver_register(&cros_platform_driver); | 649 | pr_debug("DMI Matched %s\n", dmi_id->ident); |
627 | if (ret) | 650 | |
628 | return ret; | 651 | cros_laptop = chromeos_laptop_prepare((void *)dmi_id->driver_data); |
652 | if (IS_ERR(cros_laptop)) | ||
653 | return PTR_ERR(cros_laptop); | ||
629 | 654 | ||
630 | cros_platform_device = platform_device_alloc("chromeos_laptop", -1); | 655 | error = bus_register_notifier(&i2c_bus_type, |
631 | if (!cros_platform_device) { | 656 | &chromeos_laptop_i2c_notifier); |
632 | ret = -ENOMEM; | 657 | if (error) { |
633 | goto fail_platform_device1; | 658 | pr_err("failed to register i2c bus notifier: %d\n", error); |
659 | chromeos_laptop_destroy(cros_laptop); | ||
660 | return error; | ||
634 | } | 661 | } |
635 | 662 | ||
636 | ret = platform_device_add(cros_platform_device); | 663 | /* |
637 | if (ret) | 664 | * Scan adapters that have been registered before we installed |
638 | goto fail_platform_device2; | 665 | * the notifier to make sure we do not miss any devices. |
666 | */ | ||
667 | i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter); | ||
639 | 668 | ||
640 | return 0; | 669 | return 0; |
641 | |||
642 | fail_platform_device2: | ||
643 | platform_device_put(cros_platform_device); | ||
644 | fail_platform_device1: | ||
645 | platform_driver_unregister(&cros_platform_driver); | ||
646 | return ret; | ||
647 | } | 670 | } |
648 | 671 | ||
649 | static void __exit chromeos_laptop_exit(void) | 672 | static void __exit chromeos_laptop_exit(void) |
650 | { | 673 | { |
651 | if (als) | 674 | bus_unregister_notifier(&i2c_bus_type, &chromeos_laptop_i2c_notifier); |
652 | i2c_unregister_device(als); | 675 | chromeos_laptop_destroy(cros_laptop); |
653 | if (tp) | ||
654 | i2c_unregister_device(tp); | ||
655 | if (ts) | ||
656 | i2c_unregister_device(ts); | ||
657 | |||
658 | platform_device_unregister(cros_platform_device); | ||
659 | platform_driver_unregister(&cros_platform_driver); | ||
660 | } | 676 | } |
661 | 677 | ||
662 | module_init(chromeos_laptop_init); | 678 | module_init(chromeos_laptop_init); |
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 695035a8d7fb..000000000000 --- a/include/linux/platform_data/atmel_mxt_ts.h +++ /dev/null | |||
@@ -1,31 +0,0 @@ | |||
1 | /* | ||
2 | * Atmel maXTouch Touchscreen driver | ||
3 | * | ||
4 | * Copyright (C) 2010 Samsung Electronics Co.Ltd | ||
5 | * Author: Joonyoung Shim <jy0922.shim@samsung.com> | ||
6 | * | ||
7 | * This program is free software; you can redistribute it and/or modify it | ||
8 | * under the terms of the GNU General Public License as published by the | ||
9 | * Free Software Foundation; either version 2 of the License, or (at your | ||
10 | * option) any later version. | ||
11 | */ | ||
12 | |||
13 | #ifndef __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H | ||
14 | #define __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H | ||
15 | |||
16 | #include <linux/types.h> | ||
17 | |||
18 | enum mxt_suspend_mode { | ||
19 | MXT_SUSPEND_DEEP_SLEEP = 0, | ||
20 | MXT_SUSPEND_T9_CTRL = 1, | ||
21 | }; | ||
22 | |||
23 | /* The platform data for the Atmel maXTouch touchscreen driver */ | ||
24 | struct mxt_platform_data { | ||
25 | unsigned long irqflags; | ||
26 | u8 t19_num_keys; | ||
27 | const unsigned int *t19_keymap; | ||
28 | enum mxt_suspend_mode suspend_mode; | ||
29 | }; | ||
30 | |||
31 | #endif /* __LINUX_PLATFORM_DATA_ATMEL_MXT_TS_H */ | ||