diff options
author | Clement Perrochaud <clement.perrochaud@nxp.com> | 2014-04-02 05:02:39 -0400 |
---|---|---|
committer | Samuel Ortiz <sameo@linux.intel.com> | 2014-04-21 18:37:26 -0400 |
commit | eda8565af33648aa77cc2ea6c453b7cbaf53b1f1 (patch) | |
tree | b733167b8b6f7fc6882585828125ab3c57af3dfb | |
parent | 58e1e0a920358cd0dd7fdccc8cbcaa1d117078cf (diff) |
NFC: pn544: i2c: Add device-tree (Open Firmware) support to PN544
Add functions to recover hardware resources from the device-tree when not
provided by the platform data.
Signed-off-by: Clément Perrochaud <clement.perrochaud@nxp.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r-- | drivers/nfc/pn544/i2c.c | 148 |
1 files changed, 131 insertions, 17 deletions
diff --git a/drivers/nfc/pn544/i2c.c b/drivers/nfc/pn544/i2c.c index f2acd85be86e..5239e3b54120 100644 --- a/drivers/nfc/pn544/i2c.c +++ b/drivers/nfc/pn544/i2c.c | |||
@@ -22,6 +22,8 @@ | |||
22 | #include <linux/module.h> | 22 | #include <linux/module.h> |
23 | #include <linux/i2c.h> | 23 | #include <linux/i2c.h> |
24 | #include <linux/gpio.h> | 24 | #include <linux/gpio.h> |
25 | #include <linux/of_gpio.h> | ||
26 | #include <linux/of_irq.h> | ||
25 | #include <linux/miscdevice.h> | 27 | #include <linux/miscdevice.h> |
26 | #include <linux/interrupt.h> | 28 | #include <linux/interrupt.h> |
27 | #include <linux/delay.h> | 29 | #include <linux/delay.h> |
@@ -857,6 +859,92 @@ exit_state_wait_secure_write_answer: | |||
857 | } | 859 | } |
858 | } | 860 | } |
859 | 861 | ||
862 | #ifdef CONFIG_OF | ||
863 | |||
864 | static int pn544_hci_i2c_of_request_resources(struct i2c_client *client) | ||
865 | { | ||
866 | struct pn544_i2c_phy *phy = i2c_get_clientdata(client); | ||
867 | struct device_node *pp; | ||
868 | int ret; | ||
869 | |||
870 | pp = client->dev.of_node; | ||
871 | if (!pp) { | ||
872 | ret = -ENODEV; | ||
873 | goto err_dt; | ||
874 | } | ||
875 | |||
876 | /* Obtention of EN GPIO from device tree */ | ||
877 | ret = of_get_named_gpio(pp, "enable-gpios", 0); | ||
878 | if (ret < 0) { | ||
879 | if (ret != -EPROBE_DEFER) | ||
880 | nfc_err(&client->dev, | ||
881 | "Failed to get EN gpio, error: %d\n", ret); | ||
882 | goto err_dt; | ||
883 | } | ||
884 | phy->gpio_en = ret; | ||
885 | |||
886 | /* Configuration of EN GPIO */ | ||
887 | ret = gpio_request(phy->gpio_en, "pn544_en"); | ||
888 | if (ret) { | ||
889 | nfc_err(&client->dev, "Fail EN pin\n"); | ||
890 | goto err_dt; | ||
891 | } | ||
892 | ret = gpio_direction_output(phy->gpio_en, 0); | ||
893 | if (ret) { | ||
894 | nfc_err(&client->dev, "Fail EN pin direction\n"); | ||
895 | goto err_gpio_en; | ||
896 | } | ||
897 | |||
898 | /* Obtention of FW GPIO from device tree */ | ||
899 | ret = of_get_named_gpio(pp, "firmware-gpios", 0); | ||
900 | if (ret < 0) { | ||
901 | if (ret != -EPROBE_DEFER) | ||
902 | nfc_err(&client->dev, | ||
903 | "Failed to get FW gpio, error: %d\n", ret); | ||
904 | goto err_gpio_en; | ||
905 | } | ||
906 | phy->gpio_fw = ret; | ||
907 | |||
908 | /* Configuration of FW GPIO */ | ||
909 | ret = gpio_request(phy->gpio_fw, "pn544_fw"); | ||
910 | if (ret) { | ||
911 | nfc_err(&client->dev, "Fail FW pin\n"); | ||
912 | goto err_gpio_en; | ||
913 | } | ||
914 | ret = gpio_direction_output(phy->gpio_fw, 0); | ||
915 | if (ret) { | ||
916 | nfc_err(&client->dev, "Fail FW pin direction\n"); | ||
917 | goto err_gpio_fw; | ||
918 | } | ||
919 | |||
920 | /* IRQ */ | ||
921 | ret = irq_of_parse_and_map(pp, 0); | ||
922 | if (ret < 0) { | ||
923 | nfc_err(&client->dev, | ||
924 | "Unable to get irq, error: %d\n", ret); | ||
925 | goto err_gpio_fw; | ||
926 | } | ||
927 | client->irq = ret; | ||
928 | |||
929 | return 0; | ||
930 | |||
931 | err_gpio_fw: | ||
932 | gpio_free(phy->gpio_fw); | ||
933 | err_gpio_en: | ||
934 | gpio_free(phy->gpio_en); | ||
935 | err_dt: | ||
936 | return ret; | ||
937 | } | ||
938 | |||
939 | #else | ||
940 | |||
941 | static int pn544_hci_i2c_of_request_resources(struct i2c_client *client) | ||
942 | { | ||
943 | return -ENODEV; | ||
944 | } | ||
945 | |||
946 | #endif | ||
947 | |||
860 | static int pn544_hci_i2c_probe(struct i2c_client *client, | 948 | static int pn544_hci_i2c_probe(struct i2c_client *client, |
861 | const struct i2c_device_id *id) | 949 | const struct i2c_device_id *id) |
862 | { | 950 | { |
@@ -887,25 +975,36 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, | |||
887 | i2c_set_clientdata(client, phy); | 975 | i2c_set_clientdata(client, phy); |
888 | 976 | ||
889 | pdata = client->dev.platform_data; | 977 | pdata = client->dev.platform_data; |
890 | if (pdata == NULL) { | ||
891 | nfc_err(&client->dev, "No platform data\n"); | ||
892 | return -EINVAL; | ||
893 | } | ||
894 | 978 | ||
895 | if (pdata->request_resources == NULL) { | 979 | /* No platform data, using device tree. */ |
896 | nfc_err(&client->dev, "request_resources() missing\n"); | 980 | if (!pdata && client->dev.of_node) { |
897 | return -EINVAL; | 981 | r = pn544_hci_i2c_of_request_resources(client); |
898 | } | 982 | if (r) { |
983 | nfc_err(&client->dev, "No DT data\n"); | ||
984 | return r; | ||
985 | } | ||
986 | /* Using platform data. */ | ||
987 | } else if (pdata) { | ||
899 | 988 | ||
900 | r = pdata->request_resources(client); | 989 | if (pdata->request_resources == NULL) { |
901 | if (r) { | 990 | nfc_err(&client->dev, "request_resources() missing\n"); |
902 | nfc_err(&client->dev, "Cannot get platform resources\n"); | 991 | return -EINVAL; |
903 | return r; | 992 | } |
904 | } | 993 | |
994 | r = pdata->request_resources(client); | ||
995 | if (r) { | ||
996 | nfc_err(&client->dev, | ||
997 | "Cannot get platform resources\n"); | ||
998 | return r; | ||
999 | } | ||
905 | 1000 | ||
906 | phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); | 1001 | phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); |
907 | phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); | 1002 | phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); |
908 | phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); | 1003 | phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); |
1004 | } else { | ||
1005 | nfc_err(&client->dev, "No platform data\n"); | ||
1006 | return -EINVAL; | ||
1007 | } | ||
909 | 1008 | ||
910 | pn544_hci_i2c_platform_init(phy); | 1009 | pn544_hci_i2c_platform_init(phy); |
911 | 1010 | ||
@@ -953,15 +1052,30 @@ static int pn544_hci_i2c_remove(struct i2c_client *client) | |||
953 | pn544_hci_i2c_disable(phy); | 1052 | pn544_hci_i2c_disable(phy); |
954 | 1053 | ||
955 | free_irq(client->irq, phy); | 1054 | free_irq(client->irq, phy); |
956 | if (pdata->free_resources) | 1055 | |
1056 | /* No platform data, GPIOs have been requested by this driver */ | ||
1057 | if (!pdata) { | ||
1058 | gpio_free(phy->gpio_en); | ||
1059 | gpio_free(phy->gpio_fw); | ||
1060 | /* Using platform data */ | ||
1061 | } else if (pdata->free_resources) { | ||
957 | pdata->free_resources(); | 1062 | pdata->free_resources(); |
1063 | } | ||
958 | 1064 | ||
959 | return 0; | 1065 | return 0; |
960 | } | 1066 | } |
961 | 1067 | ||
1068 | static const struct of_device_id of_pn544_i2c_match[] = { | ||
1069 | { .compatible = "nxp,pn544-i2c", }, | ||
1070 | {}, | ||
1071 | }; | ||
1072 | MODULE_DEVICE_TABLE(of, of_pn544_i2c_match); | ||
1073 | |||
962 | static struct i2c_driver pn544_hci_i2c_driver = { | 1074 | static struct i2c_driver pn544_hci_i2c_driver = { |
963 | .driver = { | 1075 | .driver = { |
964 | .name = PN544_HCI_I2C_DRIVER_NAME, | 1076 | .name = PN544_HCI_I2C_DRIVER_NAME, |
1077 | .owner = THIS_MODULE, | ||
1078 | .of_match_table = of_match_ptr(of_pn544_i2c_match), | ||
965 | }, | 1079 | }, |
966 | .probe = pn544_hci_i2c_probe, | 1080 | .probe = pn544_hci_i2c_probe, |
967 | .id_table = pn544_hci_i2c_id_table, | 1081 | .id_table = pn544_hci_i2c_id_table, |