diff options
author | Thomas Abraham <thomas.abraham@linaro.org> | 2012-07-12 18:15:15 -0400 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2012-07-13 02:23:49 -0400 |
commit | 2b90807549e5d1f700e523ddd098651ecfc18e65 (patch) | |
tree | c341f65fb5d32d81025836343f73114d2fdfc516 /drivers/spi | |
parent | 1c20c200ef96c50b3075f71220c8c8bc018a93c8 (diff) |
spi: s3c64xx: add device tree support
Add support for device based discovery.
Signed-off-by: Thomas Abraham <thomas.abraham@linaro.org>
Acked-by: Jaswinder Singh <jaswinder.singh@linaro.org>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-s3c64xx.c | 303 |
1 files changed, 264 insertions, 39 deletions
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c index e4182ea2f306..0dedbbdb153a 100644 --- a/drivers/spi/spi-s3c64xx.c +++ b/drivers/spi/spi-s3c64xx.c | |||
@@ -28,6 +28,8 @@ | |||
28 | #include <linux/pm_runtime.h> | 28 | #include <linux/pm_runtime.h> |
29 | #include <linux/spi/spi.h> | 29 | #include <linux/spi/spi.h> |
30 | #include <linux/gpio.h> | 30 | #include <linux/gpio.h> |
31 | #include <linux/of.h> | ||
32 | #include <linux/of_gpio.h> | ||
31 | 33 | ||
32 | #include <mach/dma.h> | 34 | #include <mach/dma.h> |
33 | #include <plat/s3c64xx-spi.h> | 35 | #include <plat/s3c64xx-spi.h> |
@@ -137,6 +139,7 @@ struct s3c64xx_spi_dma_data { | |||
137 | unsigned ch; | 139 | unsigned ch; |
138 | enum dma_data_direction direction; | 140 | enum dma_data_direction direction; |
139 | enum dma_ch dmach; | 141 | enum dma_ch dmach; |
142 | struct property *dma_prop; | ||
140 | }; | 143 | }; |
141 | 144 | ||
142 | /** | 145 | /** |
@@ -201,6 +204,7 @@ struct s3c64xx_spi_driver_data { | |||
201 | struct samsung_dma_ops *ops; | 204 | struct samsung_dma_ops *ops; |
202 | struct s3c64xx_spi_port_config *port_conf; | 205 | struct s3c64xx_spi_port_config *port_conf; |
203 | unsigned int port_id; | 206 | unsigned int port_id; |
207 | unsigned long gpios[4]; | ||
204 | }; | 208 | }; |
205 | 209 | ||
206 | static struct s3c2410_dma_client s3c64xx_spi_dma_client = { | 210 | static struct s3c2410_dma_client s3c64xx_spi_dma_client = { |
@@ -326,7 +330,9 @@ static int acquire_dma(struct s3c64xx_spi_driver_data *sdd) | |||
326 | req.cap = DMA_SLAVE; | 330 | req.cap = DMA_SLAVE; |
327 | req.client = &s3c64xx_spi_dma_client; | 331 | req.client = &s3c64xx_spi_dma_client; |
328 | 332 | ||
333 | req.dt_dmach_prop = sdd->rx_dma.dma_prop; | ||
329 | sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req); | 334 | sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &req); |
335 | req.dt_dmach_prop = sdd->tx_dma.dma_prop; | ||
330 | sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req); | 336 | sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &req); |
331 | 337 | ||
332 | return 1; | 338 | return 1; |
@@ -819,6 +825,48 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi) | |||
819 | return 0; | 825 | return 0; |
820 | } | 826 | } |
821 | 827 | ||
828 | static struct s3c64xx_spi_csinfo *s3c64xx_get_slave_ctrldata( | ||
829 | struct s3c64xx_spi_driver_data *sdd, | ||
830 | struct spi_device *spi) | ||
831 | { | ||
832 | struct s3c64xx_spi_csinfo *cs; | ||
833 | struct device_node *slave_np, *data_np; | ||
834 | u32 fb_delay = 0; | ||
835 | |||
836 | slave_np = spi->dev.of_node; | ||
837 | if (!slave_np) { | ||
838 | dev_err(&spi->dev, "device node not found\n"); | ||
839 | return ERR_PTR(-EINVAL); | ||
840 | } | ||
841 | |||
842 | for_each_child_of_node(slave_np, data_np) | ||
843 | if (!strcmp(data_np->name, "controller-data")) | ||
844 | break; | ||
845 | if (!data_np) { | ||
846 | dev_err(&spi->dev, "child node 'controller-data' not found\n"); | ||
847 | return ERR_PTR(-EINVAL); | ||
848 | } | ||
849 | |||
850 | cs = kzalloc(sizeof(*cs), GFP_KERNEL); | ||
851 | if (!cs) { | ||
852 | dev_err(&spi->dev, "could not allocate memory for controller" | ||
853 | " data\n"); | ||
854 | return ERR_PTR(-ENOMEM); | ||
855 | } | ||
856 | |||
857 | cs->line = of_get_named_gpio(data_np, "cs-gpio", 0); | ||
858 | if (!gpio_is_valid(cs->line)) { | ||
859 | dev_err(&spi->dev, "chip select gpio is not specified or " | ||
860 | "invalid\n"); | ||
861 | kfree(cs); | ||
862 | return ERR_PTR(-EINVAL); | ||
863 | } | ||
864 | |||
865 | of_property_read_u32(data_np, "samsung,spi-feedback-delay", &fb_delay); | ||
866 | cs->fb_delay = fb_delay; | ||
867 | return cs; | ||
868 | } | ||
869 | |||
822 | /* | 870 | /* |
823 | * Here we only check the validity of requested configuration | 871 | * Here we only check the validity of requested configuration |
824 | * and save the configuration in a local data-structure. | 872 | * and save the configuration in a local data-structure. |
@@ -832,9 +880,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
832 | struct s3c64xx_spi_info *sci; | 880 | struct s3c64xx_spi_info *sci; |
833 | struct spi_message *msg; | 881 | struct spi_message *msg; |
834 | unsigned long flags; | 882 | unsigned long flags; |
835 | int err = 0; | 883 | int err; |
836 | 884 | ||
837 | if (cs == NULL) { | 885 | sdd = spi_master_get_devdata(spi->master); |
886 | if (!cs && spi->dev.of_node) { | ||
887 | cs = s3c64xx_get_slave_ctrldata(sdd, spi); | ||
888 | spi->controller_data = cs; | ||
889 | } | ||
890 | |||
891 | if (IS_ERR_OR_NULL(cs)) { | ||
838 | dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select); | 892 | dev_err(&spi->dev, "No CS for SPI(%d)\n", spi->chip_select); |
839 | return -ENODEV; | 893 | return -ENODEV; |
840 | } | 894 | } |
@@ -844,12 +898,12 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
844 | if (err) { | 898 | if (err) { |
845 | dev_err(&spi->dev, "request for slave select gpio " | 899 | dev_err(&spi->dev, "request for slave select gpio " |
846 | "line [%d] failed\n", cs->line); | 900 | "line [%d] failed\n", cs->line); |
847 | return -EBUSY; | 901 | err = -EBUSY; |
902 | goto err_gpio_req; | ||
848 | } | 903 | } |
849 | spi_set_ctldata(spi, cs); | 904 | spi_set_ctldata(spi, cs); |
850 | } | 905 | } |
851 | 906 | ||
852 | sdd = spi_master_get_devdata(spi->master); | ||
853 | sci = sdd->cntrlr_info; | 907 | sci = sdd->cntrlr_info; |
854 | 908 | ||
855 | spin_lock_irqsave(&sdd->lock, flags); | 909 | spin_lock_irqsave(&sdd->lock, flags); |
@@ -860,7 +914,8 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
860 | dev_err(&spi->dev, | 914 | dev_err(&spi->dev, |
861 | "setup: attempt while mssg in queue!\n"); | 915 | "setup: attempt while mssg in queue!\n"); |
862 | spin_unlock_irqrestore(&sdd->lock, flags); | 916 | spin_unlock_irqrestore(&sdd->lock, flags); |
863 | return -EBUSY; | 917 | err = -EBUSY; |
918 | goto err_msgq; | ||
864 | } | 919 | } |
865 | } | 920 | } |
866 | 921 | ||
@@ -903,19 +958,29 @@ static int s3c64xx_spi_setup(struct spi_device *spi) | |||
903 | } | 958 | } |
904 | 959 | ||
905 | speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); | 960 | speed = clk_get_rate(sdd->src_clk) / 2 / (psr + 1); |
906 | if (spi->max_speed_hz >= speed) | 961 | if (spi->max_speed_hz >= speed) { |
907 | spi->max_speed_hz = speed; | 962 | spi->max_speed_hz = speed; |
908 | else | 963 | } else { |
909 | err = -EINVAL; | 964 | err = -EINVAL; |
965 | goto setup_exit; | ||
966 | } | ||
910 | } | 967 | } |
911 | 968 | ||
912 | pm_runtime_put(&sdd->pdev->dev); | 969 | pm_runtime_put(&sdd->pdev->dev); |
970 | disable_cs(sdd, spi); | ||
971 | return 0; | ||
913 | 972 | ||
914 | setup_exit: | 973 | setup_exit: |
915 | |||
916 | /* setup() returns with device de-selected */ | 974 | /* setup() returns with device de-selected */ |
917 | disable_cs(sdd, spi); | 975 | disable_cs(sdd, spi); |
918 | 976 | ||
977 | err_msgq: | ||
978 | gpio_free(cs->line); | ||
979 | spi_set_ctldata(spi, NULL); | ||
980 | |||
981 | err_gpio_req: | ||
982 | kfree(cs); | ||
983 | |||
919 | return err; | 984 | return err; |
920 | } | 985 | } |
921 | 986 | ||
@@ -923,8 +988,11 @@ static void s3c64xx_spi_cleanup(struct spi_device *spi) | |||
923 | { | 988 | { |
924 | struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi); | 989 | struct s3c64xx_spi_csinfo *cs = spi_get_ctldata(spi); |
925 | 990 | ||
926 | if (cs) | 991 | if (cs) { |
927 | gpio_free(cs->line); | 992 | gpio_free(cs->line); |
993 | if (spi->dev.of_node) | ||
994 | kfree(cs); | ||
995 | } | ||
928 | spi_set_ctldata(spi, NULL); | 996 | spi_set_ctldata(spi, NULL); |
929 | } | 997 | } |
930 | 998 | ||
@@ -989,49 +1057,166 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) | |||
989 | flush_fifo(sdd); | 1057 | flush_fifo(sdd); |
990 | } | 1058 | } |
991 | 1059 | ||
1060 | static int __devinit s3c64xx_spi_get_dmares( | ||
1061 | struct s3c64xx_spi_driver_data *sdd, bool tx) | ||
1062 | { | ||
1063 | struct platform_device *pdev = sdd->pdev; | ||
1064 | struct s3c64xx_spi_dma_data *dma_data; | ||
1065 | struct property *prop; | ||
1066 | struct resource *res; | ||
1067 | char prop_name[15], *chan_str; | ||
1068 | |||
1069 | if (tx) { | ||
1070 | dma_data = &sdd->tx_dma; | ||
1071 | dma_data->direction = DMA_TO_DEVICE; | ||
1072 | chan_str = "tx"; | ||
1073 | } else { | ||
1074 | dma_data = &sdd->rx_dma; | ||
1075 | dma_data->direction = DMA_FROM_DEVICE; | ||
1076 | chan_str = "rx"; | ||
1077 | } | ||
1078 | |||
1079 | if (!sdd->pdev->dev.of_node) { | ||
1080 | res = platform_get_resource(pdev, IORESOURCE_DMA, tx ? 0 : 1); | ||
1081 | if (!res) { | ||
1082 | dev_err(&pdev->dev, "Unable to get SPI-%s dma " | ||
1083 | "resource\n", chan_str); | ||
1084 | return -ENXIO; | ||
1085 | } | ||
1086 | dma_data->dmach = res->start; | ||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | sprintf(prop_name, "%s-dma-channel", chan_str); | ||
1091 | prop = of_find_property(pdev->dev.of_node, prop_name, NULL); | ||
1092 | if (!prop) { | ||
1093 | dev_err(&pdev->dev, "%s dma channel property not specified\n", | ||
1094 | chan_str); | ||
1095 | return -ENXIO; | ||
1096 | } | ||
1097 | |||
1098 | dma_data->dmach = DMACH_DT_PROP; | ||
1099 | dma_data->dma_prop = prop; | ||
1100 | return 0; | ||
1101 | } | ||
1102 | |||
1103 | #ifdef CONFIG_OF | ||
1104 | static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd) | ||
1105 | { | ||
1106 | struct device *dev = &sdd->pdev->dev; | ||
1107 | int idx, gpio, ret; | ||
1108 | |||
1109 | /* find gpios for mosi, miso and clock lines */ | ||
1110 | for (idx = 0; idx < 3; idx++) { | ||
1111 | gpio = of_get_gpio(dev->of_node, idx); | ||
1112 | if (!gpio_is_valid(gpio)) { | ||
1113 | dev_err(dev, "invalid gpio[%d]: %d\n", idx, gpio); | ||
1114 | goto free_gpio; | ||
1115 | } | ||
1116 | |||
1117 | ret = gpio_request(gpio, "spi-bus"); | ||
1118 | if (ret) { | ||
1119 | dev_err(dev, "gpio [%d] request failed\n", gpio); | ||
1120 | goto free_gpio; | ||
1121 | } | ||
1122 | } | ||
1123 | return 0; | ||
1124 | |||
1125 | free_gpio: | ||
1126 | while (--idx >= 0) | ||
1127 | gpio_free(sdd->gpios[idx]); | ||
1128 | return -EINVAL; | ||
1129 | } | ||
1130 | |||
1131 | static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd) | ||
1132 | { | ||
1133 | unsigned int idx; | ||
1134 | for (idx = 0; idx < 3; idx++) | ||
1135 | gpio_free(sdd->gpios[idx]); | ||
1136 | } | ||
1137 | |||
1138 | static struct __devinit s3c64xx_spi_info * s3c64xx_spi_parse_dt( | ||
1139 | struct device *dev) | ||
1140 | { | ||
1141 | struct s3c64xx_spi_info *sci; | ||
1142 | u32 temp; | ||
1143 | |||
1144 | sci = devm_kzalloc(dev, sizeof(*sci), GFP_KERNEL); | ||
1145 | if (!sci) { | ||
1146 | dev_err(dev, "memory allocation for spi_info failed\n"); | ||
1147 | return ERR_PTR(-ENOMEM); | ||
1148 | } | ||
1149 | |||
1150 | if (of_property_read_u32(dev->of_node, "samsung,spi-src-clk", &temp)) { | ||
1151 | dev_warn(dev, "spi bus clock parent not specified, using " | ||
1152 | "clock at index 0 as parent\n"); | ||
1153 | sci->src_clk_nr = 0; | ||
1154 | } else { | ||
1155 | sci->src_clk_nr = temp; | ||
1156 | } | ||
1157 | |||
1158 | if (of_property_read_u32(dev->of_node, "num-cs", &temp)) { | ||
1159 | dev_warn(dev, "number of chip select lines not specified, " | ||
1160 | "assuming 1 chip select line\n"); | ||
1161 | sci->num_cs = 1; | ||
1162 | } else { | ||
1163 | sci->num_cs = temp; | ||
1164 | } | ||
1165 | |||
1166 | return sci; | ||
1167 | } | ||
1168 | #else | ||
1169 | static struct s3c64xx_spi_info *s3c64xx_spi_parse_dt(struct device *dev) | ||
1170 | { | ||
1171 | return dev->platform_data; | ||
1172 | } | ||
1173 | |||
1174 | static int s3c64xx_spi_parse_dt_gpio(struct s3c64xx_spi_driver_data *sdd) | ||
1175 | { | ||
1176 | return -EINVAL; | ||
1177 | } | ||
1178 | |||
1179 | static void s3c64xx_spi_dt_gpio_free(struct s3c64xx_spi_driver_data *sdd) | ||
1180 | { | ||
1181 | } | ||
1182 | #endif | ||
1183 | |||
1184 | static const struct of_device_id s3c64xx_spi_dt_match[]; | ||
1185 | |||
992 | static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config( | 1186 | static inline struct s3c64xx_spi_port_config *s3c64xx_spi_get_port_config( |
993 | struct platform_device *pdev) | 1187 | struct platform_device *pdev) |
994 | { | 1188 | { |
1189 | #ifdef CONFIG_OF | ||
1190 | if (pdev->dev.of_node) { | ||
1191 | const struct of_device_id *match; | ||
1192 | match = of_match_node(s3c64xx_spi_dt_match, pdev->dev.of_node); | ||
1193 | return (struct s3c64xx_spi_port_config *)match->data; | ||
1194 | } | ||
1195 | #endif | ||
995 | return (struct s3c64xx_spi_port_config *) | 1196 | return (struct s3c64xx_spi_port_config *) |
996 | platform_get_device_id(pdev)->driver_data; | 1197 | platform_get_device_id(pdev)->driver_data; |
997 | } | 1198 | } |
998 | 1199 | ||
999 | static int __init s3c64xx_spi_probe(struct platform_device *pdev) | 1200 | static int __init s3c64xx_spi_probe(struct platform_device *pdev) |
1000 | { | 1201 | { |
1001 | struct resource *mem_res, *dmatx_res, *dmarx_res; | 1202 | struct resource *mem_res; |
1002 | struct s3c64xx_spi_driver_data *sdd; | 1203 | struct s3c64xx_spi_driver_data *sdd; |
1003 | struct s3c64xx_spi_info *sci; | 1204 | struct s3c64xx_spi_info *sci = pdev->dev.platform_data; |
1004 | struct spi_master *master; | 1205 | struct spi_master *master; |
1005 | int ret, irq; | 1206 | int ret, irq; |
1006 | char clk_name[16]; | 1207 | char clk_name[16]; |
1007 | 1208 | ||
1008 | if (pdev->id < 0) { | 1209 | if (!sci && pdev->dev.of_node) { |
1009 | dev_err(&pdev->dev, | 1210 | sci = s3c64xx_spi_parse_dt(&pdev->dev); |
1010 | "Invalid platform device id-%d\n", pdev->id); | 1211 | if (IS_ERR(sci)) |
1011 | return -ENODEV; | 1212 | return PTR_ERR(sci); |
1012 | } | 1213 | } |
1013 | 1214 | ||
1014 | if (pdev->dev.platform_data == NULL) { | 1215 | if (!sci) { |
1015 | dev_err(&pdev->dev, "platform_data missing!\n"); | 1216 | dev_err(&pdev->dev, "platform_data missing!\n"); |
1016 | return -ENODEV; | 1217 | return -ENODEV; |
1017 | } | 1218 | } |
1018 | 1219 | ||
1019 | sci = pdev->dev.platform_data; | ||
1020 | |||
1021 | /* Check for availability of necessary resource */ | ||
1022 | |||
1023 | dmatx_res = platform_get_resource(pdev, IORESOURCE_DMA, 0); | ||
1024 | if (dmatx_res == NULL) { | ||
1025 | dev_err(&pdev->dev, "Unable to get SPI-Tx dma resource\n"); | ||
1026 | return -ENXIO; | ||
1027 | } | ||
1028 | |||
1029 | dmarx_res = platform_get_resource(pdev, IORESOURCE_DMA, 1); | ||
1030 | if (dmarx_res == NULL) { | ||
1031 | dev_err(&pdev->dev, "Unable to get SPI-Rx dma resource\n"); | ||
1032 | return -ENXIO; | ||
1033 | } | ||
1034 | |||
1035 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1220 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
1036 | if (mem_res == NULL) { | 1221 | if (mem_res == NULL) { |
1037 | dev_err(&pdev->dev, "Unable to get SPI MEM resource\n"); | 1222 | dev_err(&pdev->dev, "Unable to get SPI MEM resource\n"); |
@@ -1059,14 +1244,29 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) | |||
1059 | sdd->cntrlr_info = sci; | 1244 | sdd->cntrlr_info = sci; |
1060 | sdd->pdev = pdev; | 1245 | sdd->pdev = pdev; |
1061 | sdd->sfr_start = mem_res->start; | 1246 | sdd->sfr_start = mem_res->start; |
1062 | sdd->tx_dma.dmach = dmatx_res->start; | 1247 | if (pdev->dev.of_node) { |
1063 | sdd->tx_dma.direction = DMA_MEM_TO_DEV; | 1248 | ret = of_alias_get_id(pdev->dev.of_node, "spi"); |
1064 | sdd->rx_dma.dmach = dmarx_res->start; | 1249 | if (ret < 0) { |
1065 | sdd->rx_dma.direction = DMA_DEV_TO_MEM; | 1250 | dev_err(&pdev->dev, "failed to get alias id, " |
1066 | sdd->port_id = pdev->id; | 1251 | "errno %d\n", ret); |
1252 | goto err0; | ||
1253 | } | ||
1254 | sdd->port_id = ret; | ||
1255 | } else { | ||
1256 | sdd->port_id = pdev->id; | ||
1257 | } | ||
1067 | 1258 | ||
1068 | sdd->cur_bpw = 8; | 1259 | sdd->cur_bpw = 8; |
1069 | 1260 | ||
1261 | ret = s3c64xx_spi_get_dmares(sdd, true); | ||
1262 | if (ret) | ||
1263 | goto err0; | ||
1264 | |||
1265 | ret = s3c64xx_spi_get_dmares(sdd, false); | ||
1266 | if (ret) | ||
1267 | goto err0; | ||
1268 | |||
1269 | master->dev.of_node = pdev->dev.of_node; | ||
1070 | master->bus_num = sdd->port_id; | 1270 | master->bus_num = sdd->port_id; |
1071 | master->setup = s3c64xx_spi_setup; | 1271 | master->setup = s3c64xx_spi_setup; |
1072 | master->cleanup = s3c64xx_spi_cleanup; | 1272 | master->cleanup = s3c64xx_spi_cleanup; |
@@ -1092,7 +1292,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev) | |||
1092 | goto err1; | 1292 | goto err1; |
1093 | } | 1293 | } |
1094 | 1294 | ||
1095 | if (sci->cfg_gpio == NULL || sci->cfg_gpio()) { | 1295 | if (!sci->cfg_gpio && pdev->dev.of_node) { |
1296 | if (s3c64xx_spi_parse_dt_gpio(sdd)) | ||
1297 | return -EBUSY; | ||
1298 | } else if (sci->cfg_gpio == NULL || sci->cfg_gpio()) { | ||
1096 | dev_err(&pdev->dev, "Unable to config gpio\n"); | 1299 | dev_err(&pdev->dev, "Unable to config gpio\n"); |
1097 | ret = -EBUSY; | 1300 | ret = -EBUSY; |
1098 | goto err2; | 1301 | goto err2; |
@@ -1173,6 +1376,8 @@ err5: | |||
1173 | err4: | 1376 | err4: |
1174 | clk_put(sdd->clk); | 1377 | clk_put(sdd->clk); |
1175 | err3: | 1378 | err3: |
1379 | if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node) | ||
1380 | s3c64xx_spi_dt_gpio_free(sdd); | ||
1176 | err2: | 1381 | err2: |
1177 | iounmap((void *) sdd->regs); | 1382 | iounmap((void *) sdd->regs); |
1178 | err1: | 1383 | err1: |
@@ -1204,6 +1409,9 @@ static int s3c64xx_spi_remove(struct platform_device *pdev) | |||
1204 | clk_disable(sdd->clk); | 1409 | clk_disable(sdd->clk); |
1205 | clk_put(sdd->clk); | 1410 | clk_put(sdd->clk); |
1206 | 1411 | ||
1412 | if (!sdd->cntrlr_info->cfg_gpio && pdev->dev.of_node) | ||
1413 | s3c64xx_spi_dt_gpio_free(sdd); | ||
1414 | |||
1207 | iounmap((void *) sdd->regs); | 1415 | iounmap((void *) sdd->regs); |
1208 | 1416 | ||
1209 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); | 1417 | mem_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
@@ -1228,6 +1436,9 @@ static int s3c64xx_spi_suspend(struct device *dev) | |||
1228 | clk_disable(sdd->src_clk); | 1436 | clk_disable(sdd->src_clk); |
1229 | clk_disable(sdd->clk); | 1437 | clk_disable(sdd->clk); |
1230 | 1438 | ||
1439 | if (!sdd->cntrlr_info->cfg_gpio && dev->of_node) | ||
1440 | s3c64xx_spi_dt_gpio_free(sdd); | ||
1441 | |||
1231 | sdd->cur_speed = 0; /* Output Clock is stopped */ | 1442 | sdd->cur_speed = 0; /* Output Clock is stopped */ |
1232 | 1443 | ||
1233 | return 0; | 1444 | return 0; |
@@ -1239,7 +1450,10 @@ static int s3c64xx_spi_resume(struct device *dev) | |||
1239 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); | 1450 | struct s3c64xx_spi_driver_data *sdd = spi_master_get_devdata(master); |
1240 | struct s3c64xx_spi_info *sci = sdd->cntrlr_info; | 1451 | struct s3c64xx_spi_info *sci = sdd->cntrlr_info; |
1241 | 1452 | ||
1242 | sci->cfg_gpio(); | 1453 | if (!sci->cfg_gpio && dev->of_node) |
1454 | s3c64xx_spi_parse_dt_gpio(sdd); | ||
1455 | else | ||
1456 | sci->cfg_gpio(); | ||
1243 | 1457 | ||
1244 | /* Enable the clock */ | 1458 | /* Enable the clock */ |
1245 | clk_enable(sdd->src_clk); | 1459 | clk_enable(sdd->src_clk); |
@@ -1347,11 +1561,22 @@ static struct platform_device_id s3c64xx_spi_driver_ids[] = { | |||
1347 | { }, | 1561 | { }, |
1348 | }; | 1562 | }; |
1349 | 1563 | ||
1564 | #ifdef CONFIG_OF | ||
1565 | static const struct of_device_id s3c64xx_spi_dt_match[] = { | ||
1566 | { .compatible = "samsung,exynos4210-spi", | ||
1567 | .data = (void *)&exynos4_spi_port_config, | ||
1568 | }, | ||
1569 | { }, | ||
1570 | }; | ||
1571 | MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match); | ||
1572 | #endif /* CONFIG_OF */ | ||
1573 | |||
1350 | static struct platform_driver s3c64xx_spi_driver = { | 1574 | static struct platform_driver s3c64xx_spi_driver = { |
1351 | .driver = { | 1575 | .driver = { |
1352 | .name = "s3c64xx-spi", | 1576 | .name = "s3c64xx-spi", |
1353 | .owner = THIS_MODULE, | 1577 | .owner = THIS_MODULE, |
1354 | .pm = &s3c64xx_spi_pm, | 1578 | .pm = &s3c64xx_spi_pm, |
1579 | .of_match_table = of_match_ptr(s3c64xx_spi_dt_match), | ||
1355 | }, | 1580 | }, |
1356 | .remove = s3c64xx_spi_remove, | 1581 | .remove = s3c64xx_spi_remove, |
1357 | .id_table = s3c64xx_spi_driver_ids, | 1582 | .id_table = s3c64xx_spi_driver_ids, |