aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2018-05-24 12:31:25 -0400
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2018-05-24 12:31:25 -0400
commiteffca7bdb3503519422f2fba5961759c0ea2ffce (patch)
tree1e800be56c7e58d9db6f58e6523cc1244be23b1a
parent754451342fc5954061ede74b0a8485ec4a4c6eaa (diff)
parent5020cd29d8bfcb3f3add43ea7d58b07011ab96d8 (diff)
Merge branch 'ib-chrome-platform-atmel-mxt-ts-device-properties' of git://git.kernel.org/pub/scm/linux/kernel/git/bleung/chrome-platform into next
Sync up with chrome-platform again to bring in device properties for Atmel touch controllers incompletely described in ACPI.
-rw-r--r--drivers/platform/chrome/chromeos_laptop.c307
1 files changed, 278 insertions, 29 deletions
diff --git a/drivers/platform/chrome/chromeos_laptop.c b/drivers/platform/chrome/chromeos_laptop.c
index 5c47f451e43b..3cecf7933f75 100644
--- a/drivers/platform/chrome/chromeos_laptop.c
+++ b/drivers/platform/chrome/chromeos_laptop.c
@@ -6,6 +6,7 @@
6 6
7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 7#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
8 8
9#include <linux/acpi.h>
9#include <linux/dmi.h> 10#include <linux/dmi.h>
10#include <linux/i2c.h> 11#include <linux/i2c.h>
11#include <linux/input.h> 12#include <linux/input.h>
@@ -54,6 +55,11 @@ struct i2c_peripheral {
54 struct i2c_client *client; 55 struct i2c_client *client;
55}; 56};
56 57
58struct acpi_peripheral {
59 char hid[ACPI_ID_LEN];
60 const struct property_entry *properties;
61};
62
57struct chromeos_laptop { 63struct chromeos_laptop {
58 /* 64 /*
59 * Note that we can't mark this pointer as const because 65 * Note that we can't mark this pointer as const because
@@ -61,6 +67,9 @@ struct chromeos_laptop {
61 */ 67 */
62 struct i2c_peripheral *i2c_peripherals; 68 struct i2c_peripheral *i2c_peripherals;
63 unsigned int num_i2c_peripherals; 69 unsigned int num_i2c_peripherals;
70
71 const struct acpi_peripheral *acpi_peripherals;
72 unsigned int num_acpi_peripherals;
64}; 73};
65 74
66static const struct chromeos_laptop *cros_laptop; 75static const struct chromeos_laptop *cros_laptop;
@@ -148,6 +157,38 @@ static void chromeos_laptop_check_adapter(struct i2c_adapter *adapter)
148 } 157 }
149} 158}
150 159
160static bool chromeos_laptop_adjust_client(struct i2c_client *client)
161{
162 const struct acpi_peripheral *acpi_dev;
163 struct acpi_device_id acpi_ids[2] = { };
164 int i;
165 int error;
166
167 if (!has_acpi_companion(&client->dev))
168 return false;
169
170 for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
171 acpi_dev = &cros_laptop->acpi_peripherals[i];
172
173 memcpy(acpi_ids[0].id, acpi_dev->hid, ACPI_ID_LEN);
174
175 if (acpi_match_device(acpi_ids, &client->dev)) {
176 error = device_add_properties(&client->dev,
177 acpi_dev->properties);
178 if (error) {
179 dev_err(&client->dev,
180 "failed to add properties: %d\n",
181 error);
182 break;
183 }
184
185 return true;
186 }
187 }
188
189 return false;
190}
191
151static void chromeos_laptop_detach_i2c_client(struct i2c_client *client) 192static void chromeos_laptop_detach_i2c_client(struct i2c_client *client)
152{ 193{
153 struct i2c_peripheral *i2c_dev; 194 struct i2c_peripheral *i2c_dev;
@@ -170,6 +211,8 @@ static int chromeos_laptop_i2c_notifier_call(struct notifier_block *nb,
170 case BUS_NOTIFY_ADD_DEVICE: 211 case BUS_NOTIFY_ADD_DEVICE:
171 if (dev->type == &i2c_adapter_type) 212 if (dev->type == &i2c_adapter_type)
172 chromeos_laptop_check_adapter(to_i2c_adapter(dev)); 213 chromeos_laptop_check_adapter(to_i2c_adapter(dev));
214 else if (dev->type == &i2c_client_type)
215 chromeos_laptop_adjust_client(to_i2c_client(dev));
173 break; 216 break;
174 217
175 case BUS_NOTIFY_REMOVED_DEVICE: 218 case BUS_NOTIFY_REMOVED_DEVICE:
@@ -191,6 +234,12 @@ static const struct chromeos_laptop _name __initconst = { \
191 .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \ 234 .num_i2c_peripherals = ARRAY_SIZE(_name##_peripherals), \
192} 235}
193 236
237#define DECLARE_ACPI_CROS_LAPTOP(_name) \
238static const struct chromeos_laptop _name __initconst = { \
239 .acpi_peripherals = _name##_peripherals, \
240 .num_acpi_peripherals = ARRAY_SIZE(_name##_peripherals), \
241}
242
194static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = { 243static struct i2c_peripheral samsung_series_5_550_peripherals[] __initdata = {
195 /* Touchpad. */ 244 /* Touchpad. */
196 { 245 {
@@ -234,16 +283,25 @@ static const int chromebook_pixel_tp_keys[] __initconst = {
234 283
235static const struct property_entry 284static const struct property_entry
236chromebook_pixel_trackpad_props[] __initconst = { 285chromebook_pixel_trackpad_props[] __initconst = {
286 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
237 PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys), 287 PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", chromebook_pixel_tp_keys),
238 { } 288 { }
239}; 289};
240 290
291static const struct property_entry
292chromebook_atmel_touchscreen_props[] __initconst = {
293 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
294 { }
295};
296
241static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = { 297static struct i2c_peripheral chromebook_pixel_peripherals[] __initdata = {
242 /* Touch Screen. */ 298 /* Touch Screen. */
243 { 299 {
244 .board_info = { 300 .board_info = {
245 I2C_BOARD_INFO("atmel_mxt_ts", 301 I2C_BOARD_INFO("atmel_mxt_ts",
246 ATMEL_TS_I2C_ADDR), 302 ATMEL_TS_I2C_ADDR),
303 .properties =
304 chromebook_atmel_touchscreen_props,
247 .flags = I2C_CLIENT_WAKE, 305 .flags = I2C_CLIENT_WAKE,
248 }, 306 },
249 .dmi_name = "touchscreen", 307 .dmi_name = "touchscreen",
@@ -354,6 +412,8 @@ static struct i2c_peripheral acer_c720_peripherals[] __initdata = {
354 .board_info = { 412 .board_info = {
355 I2C_BOARD_INFO("atmel_mxt_ts", 413 I2C_BOARD_INFO("atmel_mxt_ts",
356 ATMEL_TS_I2C_ADDR), 414 ATMEL_TS_I2C_ADDR),
415 .properties =
416 chromebook_atmel_touchscreen_props,
357 .flags = I2C_CLIENT_WAKE, 417 .flags = I2C_CLIENT_WAKE,
358 }, 418 },
359 .dmi_name = "touchscreen", 419 .dmi_name = "touchscreen",
@@ -419,6 +479,47 @@ static struct i2c_peripheral cr48_peripherals[] __initdata = {
419}; 479};
420DECLARE_CROS_LAPTOP(cr48); 480DECLARE_CROS_LAPTOP(cr48);
421 481
482static const u32 samus_touchpad_buttons[] __initconst = {
483 KEY_RESERVED,
484 KEY_RESERVED,
485 KEY_RESERVED,
486 BTN_LEFT
487};
488
489static const struct property_entry samus_trackpad_props[] __initconst = {
490 PROPERTY_ENTRY_STRING("compatible", "atmel,maxtouch"),
491 PROPERTY_ENTRY_U32_ARRAY("linux,gpio-keymap", samus_touchpad_buttons),
492 { }
493};
494
495static struct acpi_peripheral samus_peripherals[] __initdata = {
496 /* Touchpad */
497 {
498 .hid = "ATML0000",
499 .properties = samus_trackpad_props,
500 },
501 /* Touchsceen */
502 {
503 .hid = "ATML0001",
504 .properties = chromebook_atmel_touchscreen_props,
505 },
506};
507DECLARE_ACPI_CROS_LAPTOP(samus);
508
509static struct acpi_peripheral generic_atmel_peripherals[] __initdata = {
510 /* Touchpad */
511 {
512 .hid = "ATML0000",
513 .properties = chromebook_pixel_trackpad_props,
514 },
515 /* Touchsceen */
516 {
517 .hid = "ATML0001",
518 .properties = chromebook_atmel_touchscreen_props,
519 },
520};
521DECLARE_ACPI_CROS_LAPTOP(generic_atmel);
522
422static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = { 523static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
423 { 524 {
424 .ident = "Samsung Series 5 550", 525 .ident = "Samsung Series 5 550",
@@ -502,17 +603,64 @@ static const struct dmi_system_id chromeos_laptop_dmi_table[] __initconst = {
502 }, 603 },
503 .driver_data = (void *)&cr48, 604 .driver_data = (void *)&cr48,
504 }, 605 },
606 /* Devices with peripherals incompletely described in ACPI */
607 {
608 .ident = "Chromebook Pro",
609 .matches = {
610 DMI_MATCH(DMI_SYS_VENDOR, "Google"),
611 DMI_MATCH(DMI_PRODUCT_NAME, "Caroline"),
612 },
613 .driver_data = (void *)&samus,
614 },
615 {
616 .ident = "Google Pixel 2 (2015)",
617 .matches = {
618 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
619 DMI_MATCH(DMI_PRODUCT_NAME, "Samus"),
620 },
621 .driver_data = (void *)&samus,
622 },
623 {
624 /*
625 * Other Chromebooks with Atmel touch controllers:
626 * - Celes, Winky (touchpad)
627 * - Clapper, Expresso, Rambi, Glimmer (touchscreen)
628 */
629 .ident = "Other Chromebook",
630 .matches = {
631 /*
632 * This will match all Google devices, not only devices
633 * with Atmel, but we will validate that the device
634 * actually has matching peripherals.
635 */
636 DMI_MATCH(DMI_SYS_VENDOR, "GOOGLE"),
637 },
638 .driver_data = (void *)&generic_atmel,
639 },
505 { } 640 { }
506}; 641};
507MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table); 642MODULE_DEVICE_TABLE(dmi, chromeos_laptop_dmi_table);
508 643
509static int __init chromeos_laptop_scan_adapter(struct device *dev, void *data) 644static int __init chromeos_laptop_scan_peripherals(struct device *dev, void *data)
510{ 645{
511 struct i2c_adapter *adapter; 646 int error;
512 647
513 adapter = i2c_verify_adapter(dev); 648 if (dev->type == &i2c_adapter_type) {
514 if (adapter) 649 chromeos_laptop_check_adapter(to_i2c_adapter(dev));
515 chromeos_laptop_check_adapter(adapter); 650 } else if (dev->type == &i2c_client_type) {
651 if (chromeos_laptop_adjust_client(to_i2c_client(dev))) {
652 /*
653 * Now that we have needed properties re-trigger
654 * driver probe in case driver was initialized
655 * earlier and probe failed.
656 */
657 error = device_attach(dev);
658 if (error < 0)
659 dev_warn(dev,
660 "%s: device_attach() failed: %d\n",
661 __func__, error);
662 }
663 }
516 664
517 return 0; 665 return 0;
518} 666}
@@ -556,27 +704,24 @@ static int __init chromeos_laptop_setup_irq(struct i2c_peripheral *i2c_dev)
556 return 0; 704 return 0;
557} 705}
558 706
559static struct chromeos_laptop * __init 707static int __init
560chromeos_laptop_prepare(const struct chromeos_laptop *src) 708chromeos_laptop_prepare_i2c_peripherals(struct chromeos_laptop *cros_laptop,
709 const struct chromeos_laptop *src)
561{ 710{
562 struct chromeos_laptop *cros_laptop;
563 struct i2c_peripheral *i2c_dev; 711 struct i2c_peripheral *i2c_dev;
564 struct i2c_board_info *info; 712 struct i2c_board_info *info;
565 int error;
566 int i; 713 int i;
714 int error;
567 715
568 cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL); 716 if (!src->num_i2c_peripherals)
569 if (!cros_laptop) 717 return 0;
570 return ERR_PTR(-ENOMEM);
571 718
572 cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals, 719 cros_laptop->i2c_peripherals = kmemdup(src->i2c_peripherals,
573 src->num_i2c_peripherals * 720 src->num_i2c_peripherals *
574 sizeof(*src->i2c_peripherals), 721 sizeof(*src->i2c_peripherals),
575 GFP_KERNEL); 722 GFP_KERNEL);
576 if (!cros_laptop->i2c_peripherals) { 723 if (!cros_laptop->i2c_peripherals)
577 error = -ENOMEM; 724 return -ENOMEM;
578 goto err_free_cros_laptop;
579 }
580 725
581 cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals; 726 cros_laptop->num_i2c_peripherals = src->num_i2c_peripherals;
582 727
@@ -586,7 +731,7 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src)
586 731
587 error = chromeos_laptop_setup_irq(i2c_dev); 732 error = chromeos_laptop_setup_irq(i2c_dev);
588 if (error) 733 if (error)
589 goto err_destroy_cros_peripherals; 734 goto err_out;
590 735
591 /* We need to deep-copy properties */ 736 /* We need to deep-copy properties */
592 if (info->properties) { 737 if (info->properties) {
@@ -594,14 +739,14 @@ chromeos_laptop_prepare(const struct chromeos_laptop *src)
594 property_entries_dup(info->properties); 739 property_entries_dup(info->properties);
595 if (IS_ERR(info->properties)) { 740 if (IS_ERR(info->properties)) {
596 error = PTR_ERR(info->properties); 741 error = PTR_ERR(info->properties);
597 goto err_destroy_cros_peripherals; 742 goto err_out;
598 } 743 }
599 } 744 }
600 } 745 }
601 746
602 return cros_laptop; 747 return 0;
603 748
604err_destroy_cros_peripherals: 749err_out:
605 while (--i >= 0) { 750 while (--i >= 0) {
606 i2c_dev = &cros_laptop->i2c_peripherals[i]; 751 i2c_dev = &cros_laptop->i2c_peripherals[i];
607 info = &i2c_dev->board_info; 752 info = &i2c_dev->board_info;
@@ -609,13 +754,74 @@ err_destroy_cros_peripherals:
609 property_entries_free(info->properties); 754 property_entries_free(info->properties);
610 } 755 }
611 kfree(cros_laptop->i2c_peripherals); 756 kfree(cros_laptop->i2c_peripherals);
612err_free_cros_laptop: 757 return error;
613 kfree(cros_laptop); 758}
614 return ERR_PTR(error); 759
760static int __init
761chromeos_laptop_prepare_acpi_peripherals(struct chromeos_laptop *cros_laptop,
762 const struct chromeos_laptop *src)
763{
764 struct acpi_peripheral *acpi_peripherals;
765 struct acpi_peripheral *acpi_dev;
766 const struct acpi_peripheral *src_dev;
767 int n_peripherals = 0;
768 int i;
769 int error;
770
771 for (i = 0; i < src->num_acpi_peripherals; i++) {
772 if (acpi_dev_present(src->acpi_peripherals[i].hid, NULL, -1))
773 n_peripherals++;
774 }
775
776 if (!n_peripherals)
777 return 0;
778
779 acpi_peripherals = kcalloc(n_peripherals,
780 sizeof(*src->acpi_peripherals),
781 GFP_KERNEL);
782 if (!acpi_peripherals)
783 return -ENOMEM;
784
785 acpi_dev = acpi_peripherals;
786 for (i = 0; i < src->num_acpi_peripherals; i++) {
787 src_dev = &src->acpi_peripherals[i];
788 if (!acpi_dev_present(src_dev->hid, NULL, -1))
789 continue;
790
791 *acpi_dev = *src_dev;
792
793 /* We need to deep-copy properties */
794 if (src_dev->properties) {
795 acpi_dev->properties =
796 property_entries_dup(src_dev->properties);
797 if (IS_ERR(acpi_dev->properties)) {
798 error = PTR_ERR(acpi_dev->properties);
799 goto err_out;
800 }
801 }
802
803 acpi_dev++;
804 }
805
806 cros_laptop->acpi_peripherals = acpi_peripherals;
807 cros_laptop->num_acpi_peripherals = n_peripherals;
808
809 return 0;
810
811err_out:
812 while (--i >= 0) {
813 acpi_dev = &acpi_peripherals[i];
814 if (acpi_dev->properties)
815 property_entries_free(acpi_dev->properties);
816 }
817
818 kfree(acpi_peripherals);
819 return error;
615} 820}
616 821
617static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop) 822static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
618{ 823{
824 const struct acpi_peripheral *acpi_dev;
619 struct i2c_peripheral *i2c_dev; 825 struct i2c_peripheral *i2c_dev;
620 struct i2c_board_info *info; 826 struct i2c_board_info *info;
621 int i; 827 int i;
@@ -631,10 +837,41 @@ static void chromeos_laptop_destroy(const struct chromeos_laptop *cros_laptop)
631 property_entries_free(info->properties); 837 property_entries_free(info->properties);
632 } 838 }
633 839
840 for (i = 0; i < cros_laptop->num_acpi_peripherals; i++) {
841 acpi_dev = &cros_laptop->acpi_peripherals[i];
842
843 if (acpi_dev->properties)
844 property_entries_free(acpi_dev->properties);
845 }
846
634 kfree(cros_laptop->i2c_peripherals); 847 kfree(cros_laptop->i2c_peripherals);
848 kfree(cros_laptop->acpi_peripherals);
635 kfree(cros_laptop); 849 kfree(cros_laptop);
636} 850}
637 851
852static struct chromeos_laptop * __init
853chromeos_laptop_prepare(const struct chromeos_laptop *src)
854{
855 struct chromeos_laptop *cros_laptop;
856 int error;
857
858 cros_laptop = kzalloc(sizeof(*cros_laptop), GFP_KERNEL);
859 if (!cros_laptop)
860 return ERR_PTR(-ENOMEM);
861
862 error = chromeos_laptop_prepare_i2c_peripherals(cros_laptop, src);
863 if (!error)
864 error = chromeos_laptop_prepare_acpi_peripherals(cros_laptop,
865 src);
866
867 if (error) {
868 chromeos_laptop_destroy(cros_laptop);
869 return ERR_PTR(error);
870 }
871
872 return cros_laptop;
873}
874
638static int __init chromeos_laptop_init(void) 875static int __init chromeos_laptop_init(void)
639{ 876{
640 const struct dmi_system_id *dmi_id; 877 const struct dmi_system_id *dmi_id;
@@ -652,21 +889,33 @@ static int __init chromeos_laptop_init(void)
652 if (IS_ERR(cros_laptop)) 889 if (IS_ERR(cros_laptop))
653 return PTR_ERR(cros_laptop); 890 return PTR_ERR(cros_laptop);
654 891
892 if (!cros_laptop->num_i2c_peripherals &&
893 !cros_laptop->num_acpi_peripherals) {
894 pr_debug("no relevant devices detected\n");
895 error = -ENODEV;
896 goto err_destroy_cros_laptop;
897 }
898
655 error = bus_register_notifier(&i2c_bus_type, 899 error = bus_register_notifier(&i2c_bus_type,
656 &chromeos_laptop_i2c_notifier); 900 &chromeos_laptop_i2c_notifier);
657 if (error) { 901 if (error) {
658 pr_err("failed to register i2c bus notifier: %d\n", error); 902 pr_err("failed to register i2c bus notifier: %d\n",
659 chromeos_laptop_destroy(cros_laptop); 903 error);
660 return error; 904 goto err_destroy_cros_laptop;
661 } 905 }
662 906
663 /* 907 /*
664 * Scan adapters that have been registered before we installed 908 * Scan adapters that have been registered and clients that have
665 * the notifier to make sure we do not miss any devices. 909 * been created before we installed the notifier to make sure
910 * we do not miss any devices.
666 */ 911 */
667 i2c_for_each_dev(NULL, chromeos_laptop_scan_adapter); 912 i2c_for_each_dev(NULL, chromeos_laptop_scan_peripherals);
668 913
669 return 0; 914 return 0;
915
916err_destroy_cros_laptop:
917 chromeos_laptop_destroy(cros_laptop);
918 return error;
670} 919}
671 920
672static void __exit chromeos_laptop_exit(void) 921static void __exit chromeos_laptop_exit(void)