| .. | .. |
|---|
| 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 | |
|---|