.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Description: keypad driver for ADP5589, ADP5585 |
---|
3 | 4 | * I2C QWERTY Keypad and IO Expander |
---|
4 | 5 | * Bugs: Enter bugs at http://blackfin.uclinux.org/ |
---|
5 | 6 | * |
---|
6 | 7 | * Copyright (C) 2010-2011 Analog Devices Inc. |
---|
7 | | - * Licensed under the GPL-2. |
---|
8 | 8 | */ |
---|
9 | 9 | |
---|
10 | 10 | #include <linux/module.h> |
---|
.. | .. |
---|
505 | 505 | if (!gpio_data) |
---|
506 | 506 | return 0; |
---|
507 | 507 | |
---|
| 508 | + kpad->gc.parent = dev; |
---|
508 | 509 | kpad->gc.ngpio = adp5589_build_gpiomap(kpad, pdata); |
---|
509 | 510 | if (kpad->gc.ngpio == 0) { |
---|
510 | 511 | dev_info(dev, "No unused gpios left to export\n"); |
---|
.. | .. |
---|
856 | 857 | input_sync(kpad->input); |
---|
857 | 858 | } |
---|
858 | 859 | |
---|
859 | | -static int adp5589_probe(struct i2c_client *client, |
---|
860 | | - const struct i2c_device_id *id) |
---|
| 860 | +static int adp5589_keypad_add(struct adp5589_kpad *kpad, unsigned int revid) |
---|
861 | 861 | { |
---|
862 | | - struct adp5589_kpad *kpad; |
---|
| 862 | + struct i2c_client *client = kpad->client; |
---|
863 | 863 | const struct adp5589_kpad_platform_data *pdata = |
---|
864 | 864 | dev_get_platdata(&client->dev); |
---|
865 | 865 | struct input_dev *input; |
---|
866 | | - unsigned int revid; |
---|
867 | | - int ret, i; |
---|
| 866 | + unsigned int i; |
---|
868 | 867 | int error; |
---|
869 | | - |
---|
870 | | - if (!i2c_check_functionality(client->adapter, |
---|
871 | | - I2C_FUNC_SMBUS_BYTE_DATA)) { |
---|
872 | | - dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); |
---|
873 | | - return -EIO; |
---|
874 | | - } |
---|
875 | | - |
---|
876 | | - if (!pdata) { |
---|
877 | | - dev_err(&client->dev, "no platform data?\n"); |
---|
878 | | - return -EINVAL; |
---|
879 | | - } |
---|
880 | | - |
---|
881 | | - kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); |
---|
882 | | - if (!kpad) |
---|
883 | | - return -ENOMEM; |
---|
884 | | - |
---|
885 | | - switch (id->driver_data) { |
---|
886 | | - case ADP5585_02: |
---|
887 | | - kpad->support_row5 = true; |
---|
888 | | - /* fall through */ |
---|
889 | | - case ADP5585_01: |
---|
890 | | - kpad->is_adp5585 = true; |
---|
891 | | - kpad->var = &const_adp5585; |
---|
892 | | - break; |
---|
893 | | - case ADP5589: |
---|
894 | | - kpad->support_row5 = true; |
---|
895 | | - kpad->var = &const_adp5589; |
---|
896 | | - break; |
---|
897 | | - } |
---|
898 | 868 | |
---|
899 | 869 | if (!((pdata->keypad_en_mask & kpad->var->row_mask) && |
---|
900 | 870 | (pdata->keypad_en_mask >> kpad->var->col_shift)) || |
---|
901 | 871 | !pdata->keymap) { |
---|
902 | 872 | dev_err(&client->dev, "no rows, cols or keymap from pdata\n"); |
---|
903 | | - error = -EINVAL; |
---|
904 | | - goto err_free_mem; |
---|
| 873 | + return -EINVAL; |
---|
905 | 874 | } |
---|
906 | 875 | |
---|
907 | 876 | if (pdata->keymapsize != kpad->var->keymapsize) { |
---|
908 | 877 | dev_err(&client->dev, "invalid keymapsize\n"); |
---|
909 | | - error = -EINVAL; |
---|
910 | | - goto err_free_mem; |
---|
| 878 | + return -EINVAL; |
---|
911 | 879 | } |
---|
912 | 880 | |
---|
913 | 881 | if (!pdata->gpimap && pdata->gpimapsize) { |
---|
914 | 882 | dev_err(&client->dev, "invalid gpimap from pdata\n"); |
---|
915 | | - error = -EINVAL; |
---|
916 | | - goto err_free_mem; |
---|
| 883 | + return -EINVAL; |
---|
917 | 884 | } |
---|
918 | 885 | |
---|
919 | 886 | if (pdata->gpimapsize > kpad->var->gpimapsize_max) { |
---|
920 | 887 | dev_err(&client->dev, "invalid gpimapsize\n"); |
---|
921 | | - error = -EINVAL; |
---|
922 | | - goto err_free_mem; |
---|
| 888 | + return -EINVAL; |
---|
923 | 889 | } |
---|
924 | 890 | |
---|
925 | 891 | for (i = 0; i < pdata->gpimapsize; i++) { |
---|
.. | .. |
---|
928 | 894 | if (pin < kpad->var->gpi_pin_base || |
---|
929 | 895 | pin > kpad->var->gpi_pin_end) { |
---|
930 | 896 | dev_err(&client->dev, "invalid gpi pin data\n"); |
---|
931 | | - error = -EINVAL; |
---|
932 | | - goto err_free_mem; |
---|
| 897 | + return -EINVAL; |
---|
933 | 898 | } |
---|
934 | 899 | |
---|
935 | 900 | if ((1 << (pin - kpad->var->gpi_pin_row_base)) & |
---|
936 | 901 | pdata->keypad_en_mask) { |
---|
937 | 902 | dev_err(&client->dev, "invalid gpi row/col data\n"); |
---|
938 | | - error = -EINVAL; |
---|
939 | | - goto err_free_mem; |
---|
| 903 | + return -EINVAL; |
---|
940 | 904 | } |
---|
941 | 905 | } |
---|
942 | 906 | |
---|
943 | 907 | if (!client->irq) { |
---|
944 | 908 | dev_err(&client->dev, "no IRQ?\n"); |
---|
945 | | - error = -EINVAL; |
---|
946 | | - goto err_free_mem; |
---|
| 909 | + return -EINVAL; |
---|
947 | 910 | } |
---|
948 | 911 | |
---|
949 | 912 | input = input_allocate_device(); |
---|
950 | | - if (!input) { |
---|
951 | | - error = -ENOMEM; |
---|
952 | | - goto err_free_mem; |
---|
953 | | - } |
---|
| 913 | + if (!input) |
---|
| 914 | + return -ENOMEM; |
---|
954 | 915 | |
---|
955 | | - kpad->client = client; |
---|
956 | 916 | kpad->input = input; |
---|
957 | | - |
---|
958 | | - ret = adp5589_read(client, ADP5589_5_ID); |
---|
959 | | - if (ret < 0) { |
---|
960 | | - error = ret; |
---|
961 | | - goto err_free_input; |
---|
962 | | - } |
---|
963 | | - |
---|
964 | | - revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK; |
---|
965 | 917 | |
---|
966 | 918 | input->name = client->name; |
---|
967 | 919 | input->phys = "adp5589-keys/input0"; |
---|
.. | .. |
---|
1014 | 966 | goto err_unreg_dev; |
---|
1015 | 967 | } |
---|
1016 | 968 | |
---|
| 969 | + device_init_wakeup(&client->dev, 1); |
---|
| 970 | + |
---|
| 971 | + return 0; |
---|
| 972 | + |
---|
| 973 | +err_unreg_dev: |
---|
| 974 | + input_unregister_device(input); |
---|
| 975 | + input = NULL; |
---|
| 976 | +err_free_input: |
---|
| 977 | + input_free_device(input); |
---|
| 978 | + |
---|
| 979 | + return error; |
---|
| 980 | +} |
---|
| 981 | + |
---|
| 982 | +static void adp5589_keypad_remove(struct adp5589_kpad *kpad) |
---|
| 983 | +{ |
---|
| 984 | + if (kpad->input) { |
---|
| 985 | + free_irq(kpad->client->irq, kpad); |
---|
| 986 | + input_unregister_device(kpad->input); |
---|
| 987 | + } |
---|
| 988 | +} |
---|
| 989 | + |
---|
| 990 | +static int adp5589_probe(struct i2c_client *client, |
---|
| 991 | + const struct i2c_device_id *id) |
---|
| 992 | +{ |
---|
| 993 | + struct adp5589_kpad *kpad; |
---|
| 994 | + const struct adp5589_kpad_platform_data *pdata = |
---|
| 995 | + dev_get_platdata(&client->dev); |
---|
| 996 | + unsigned int revid; |
---|
| 997 | + int error, ret; |
---|
| 998 | + |
---|
| 999 | + if (!i2c_check_functionality(client->adapter, |
---|
| 1000 | + I2C_FUNC_SMBUS_BYTE_DATA)) { |
---|
| 1001 | + dev_err(&client->dev, "SMBUS Byte Data not Supported\n"); |
---|
| 1002 | + return -EIO; |
---|
| 1003 | + } |
---|
| 1004 | + |
---|
| 1005 | + if (!pdata) { |
---|
| 1006 | + dev_err(&client->dev, "no platform data?\n"); |
---|
| 1007 | + return -EINVAL; |
---|
| 1008 | + } |
---|
| 1009 | + |
---|
| 1010 | + kpad = kzalloc(sizeof(*kpad), GFP_KERNEL); |
---|
| 1011 | + if (!kpad) |
---|
| 1012 | + return -ENOMEM; |
---|
| 1013 | + |
---|
| 1014 | + kpad->client = client; |
---|
| 1015 | + |
---|
| 1016 | + switch (id->driver_data) { |
---|
| 1017 | + case ADP5585_02: |
---|
| 1018 | + kpad->support_row5 = true; |
---|
| 1019 | + fallthrough; |
---|
| 1020 | + case ADP5585_01: |
---|
| 1021 | + kpad->is_adp5585 = true; |
---|
| 1022 | + kpad->var = &const_adp5585; |
---|
| 1023 | + break; |
---|
| 1024 | + case ADP5589: |
---|
| 1025 | + kpad->support_row5 = true; |
---|
| 1026 | + kpad->var = &const_adp5589; |
---|
| 1027 | + break; |
---|
| 1028 | + } |
---|
| 1029 | + |
---|
| 1030 | + ret = adp5589_read(client, ADP5589_5_ID); |
---|
| 1031 | + if (ret < 0) { |
---|
| 1032 | + error = ret; |
---|
| 1033 | + goto err_free_mem; |
---|
| 1034 | + } |
---|
| 1035 | + |
---|
| 1036 | + revid = (u8) ret & ADP5589_5_DEVICE_ID_MASK; |
---|
| 1037 | + |
---|
| 1038 | + if (pdata->keymapsize) { |
---|
| 1039 | + error = adp5589_keypad_add(kpad, revid); |
---|
| 1040 | + if (error) |
---|
| 1041 | + goto err_free_mem; |
---|
| 1042 | + } |
---|
| 1043 | + |
---|
1017 | 1044 | error = adp5589_setup(kpad); |
---|
1018 | 1045 | if (error) |
---|
1019 | | - goto err_free_irq; |
---|
| 1046 | + goto err_keypad_remove; |
---|
1020 | 1047 | |
---|
1021 | 1048 | if (kpad->gpimapsize) |
---|
1022 | 1049 | adp5589_report_switch_state(kpad); |
---|
1023 | 1050 | |
---|
1024 | 1051 | error = adp5589_gpio_add(kpad); |
---|
1025 | 1052 | if (error) |
---|
1026 | | - goto err_free_irq; |
---|
| 1053 | + goto err_keypad_remove; |
---|
1027 | 1054 | |
---|
1028 | | - device_init_wakeup(&client->dev, 1); |
---|
1029 | 1055 | i2c_set_clientdata(client, kpad); |
---|
1030 | 1056 | |
---|
1031 | 1057 | dev_info(&client->dev, "Rev.%d keypad, irq %d\n", revid, client->irq); |
---|
1032 | 1058 | return 0; |
---|
1033 | 1059 | |
---|
1034 | | -err_free_irq: |
---|
1035 | | - free_irq(client->irq, kpad); |
---|
1036 | | -err_unreg_dev: |
---|
1037 | | - input_unregister_device(input); |
---|
1038 | | - input = NULL; |
---|
1039 | | -err_free_input: |
---|
1040 | | - input_free_device(input); |
---|
| 1060 | +err_keypad_remove: |
---|
| 1061 | + adp5589_keypad_remove(kpad); |
---|
1041 | 1062 | err_free_mem: |
---|
1042 | 1063 | kfree(kpad); |
---|
1043 | 1064 | |
---|
.. | .. |
---|
1049 | 1070 | struct adp5589_kpad *kpad = i2c_get_clientdata(client); |
---|
1050 | 1071 | |
---|
1051 | 1072 | adp5589_write(client, kpad->var->reg(ADP5589_GENERAL_CFG), 0); |
---|
1052 | | - free_irq(client->irq, kpad); |
---|
1053 | | - input_unregister_device(kpad->input); |
---|
| 1073 | + adp5589_keypad_remove(kpad); |
---|
1054 | 1074 | adp5589_gpio_remove(kpad); |
---|
1055 | 1075 | kfree(kpad); |
---|
1056 | 1076 | |
---|
.. | .. |
---|
1062 | 1082 | { |
---|
1063 | 1083 | struct adp5589_kpad *kpad = dev_get_drvdata(dev); |
---|
1064 | 1084 | struct i2c_client *client = kpad->client; |
---|
| 1085 | + |
---|
| 1086 | + if (!kpad->input) |
---|
| 1087 | + return 0; |
---|
1065 | 1088 | |
---|
1066 | 1089 | disable_irq(client->irq); |
---|
1067 | 1090 | |
---|
.. | .. |
---|
1076 | 1099 | struct adp5589_kpad *kpad = dev_get_drvdata(dev); |
---|
1077 | 1100 | struct i2c_client *client = kpad->client; |
---|
1078 | 1101 | |
---|
| 1102 | + if (!kpad->input) |
---|
| 1103 | + return 0; |
---|
| 1104 | + |
---|
1079 | 1105 | if (device_may_wakeup(&client->dev)) |
---|
1080 | 1106 | disable_irq_wake(client->irq); |
---|
1081 | 1107 | |
---|