diff options
author | Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com> | 2011-06-07 01:50:10 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@secretlab.ca> | 2011-06-08 18:53:48 -0400 |
commit | f016aeb655350ef935ddf336e22cb00452a1c41e (patch) | |
tree | ec3642a02c7b0358fbb8a7fe2ce9bb3f9c3cc7d3 /drivers/spi/spi-topcliff-pch.c | |
parent | ca632f556697d45d67ed5cada7cedf3ddfe0db4b (diff) |
spi/topcliff_pch: support new device ML7213 IOH
Support ML7213 device of OKI SEMICONDUCTOR.
ML7213 is companion chip of Intel Atom E6xx series for IVI(In-Vehicle Infotainment).
ML7213 is compatible for Intel EG20T PCH.
v4: - Delete unrelated whitespace
- Prevent device driver from accessing platform data
- Add __devinit and __devexit
- Save pdev->dev to pd_dev->dev.parent
- Have own suspend/resume processing in platform_driver.
- Care returned value in pch_spi_init
- Change unregister order
Signed-off-by: Tomoya MORINAGA <tomoya-linux@dsn.okisemi.com>
Signed-off-by: Grant Likely <grant.likely@secretlab.ca>
Diffstat (limited to 'drivers/spi/spi-topcliff-pch.c')
-rw-r--r-- | drivers/spi/spi-topcliff-pch.c | 587 |
1 files changed, 308 insertions, 279 deletions
diff --git a/drivers/spi/spi-topcliff-pch.c b/drivers/spi/spi-topcliff-pch.c index 79e48d451137..be84e3a36406 100644 --- a/drivers/spi/spi-topcliff-pch.c +++ b/drivers/spi/spi-topcliff-pch.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/spi/spidev.h> | 26 | #include <linux/spi/spidev.h> |
27 | #include <linux/module.h> | 27 | #include <linux/module.h> |
28 | #include <linux/device.h> | 28 | #include <linux/device.h> |
29 | #include <linux/platform_device.h> | ||
29 | 30 | ||
30 | /* Register offsets */ | 31 | /* Register offsets */ |
31 | #define PCH_SPCR 0x00 /* SPI control register */ | 32 | #define PCH_SPCR 0x00 /* SPI control register */ |
@@ -35,6 +36,7 @@ | |||
35 | #define PCH_SPDRR 0x10 /* SPI read data register */ | 36 | #define PCH_SPDRR 0x10 /* SPI read data register */ |
36 | #define PCH_SSNXCR 0x18 /* SSN Expand Control Register */ | 37 | #define PCH_SSNXCR 0x18 /* SSN Expand Control Register */ |
37 | #define PCH_SRST 0x1C /* SPI reset register */ | 38 | #define PCH_SRST 0x1C /* SPI reset register */ |
39 | #define PCH_SPI_ADDRESS_SIZE 0x20 | ||
38 | 40 | ||
39 | #define PCH_SPSR_TFD 0x000007C0 | 41 | #define PCH_SPSR_TFD 0x000007C0 |
40 | #define PCH_SPSR_RFD 0x0000F800 | 42 | #define PCH_SPSR_RFD 0x0000F800 |
@@ -75,7 +77,8 @@ | |||
75 | #define SPSR_FI_BIT (1 << 2) | 77 | #define SPSR_FI_BIT (1 << 2) |
76 | #define SPBRR_SIZE_BIT (1 << 10) | 78 | #define SPBRR_SIZE_BIT (1 << 10) |
77 | 79 | ||
78 | #define PCH_ALL (SPCR_TFIE_BIT|SPCR_RFIE_BIT|SPCR_FIE_BIT|SPCR_ORIE_BIT|SPCR_MDFIE_BIT) | 80 | #define PCH_ALL (SPCR_TFIE_BIT|SPCR_RFIE_BIT|SPCR_FIE_BIT|\ |
81 | SPCR_ORIE_BIT|SPCR_MDFIE_BIT) | ||
79 | 82 | ||
80 | #define SPCR_RFIC_FIELD 20 | 83 | #define SPCR_RFIC_FIELD 20 |
81 | #define SPCR_TFIC_FIELD 16 | 84 | #define SPCR_TFIC_FIELD 16 |
@@ -88,6 +91,16 @@ | |||
88 | #define PCH_CLOCK_HZ 50000000 | 91 | #define PCH_CLOCK_HZ 50000000 |
89 | #define PCH_MAX_SPBR 1023 | 92 | #define PCH_MAX_SPBR 1023 |
90 | 93 | ||
94 | /* Definition for ML7213 by OKI SEMICONDUCTOR */ | ||
95 | #define PCI_VENDOR_ID_ROHM 0x10DB | ||
96 | #define PCI_DEVICE_ID_ML7213_SPI 0x802c | ||
97 | |||
98 | /* | ||
99 | * Set the number of SPI instance max | ||
100 | * Intel EG20T PCH : 1ch | ||
101 | * OKI SEMICONDUCTOR ML7213 IOH : 2ch | ||
102 | */ | ||
103 | #define PCH_SPI_MAX_DEV 2 | ||
91 | 104 | ||
92 | /** | 105 | /** |
93 | * struct pch_spi_data - Holds the SPI channel specific details | 106 | * struct pch_spi_data - Holds the SPI channel specific details |
@@ -121,6 +134,9 @@ | |||
121 | * @cur_trans: The current transfer that this SPI driver is | 134 | * @cur_trans: The current transfer that this SPI driver is |
122 | * handling | 135 | * handling |
123 | * @board_dat: Reference to the SPI device data structure | 136 | * @board_dat: Reference to the SPI device data structure |
137 | * @plat_dev: platform_device structure | ||
138 | * @ch: SPI channel number | ||
139 | * @irq_reg_sts: Status of IRQ registration | ||
124 | */ | 140 | */ |
125 | struct pch_spi_data { | 141 | struct pch_spi_data { |
126 | void __iomem *io_remap_addr; | 142 | void __iomem *io_remap_addr; |
@@ -144,27 +160,33 @@ struct pch_spi_data { | |||
144 | struct spi_message *current_msg; | 160 | struct spi_message *current_msg; |
145 | struct spi_transfer *cur_trans; | 161 | struct spi_transfer *cur_trans; |
146 | struct pch_spi_board_data *board_dat; | 162 | struct pch_spi_board_data *board_dat; |
163 | struct platform_device *plat_dev; | ||
164 | int ch; | ||
165 | u8 irq_reg_sts; | ||
147 | }; | 166 | }; |
148 | 167 | ||
149 | /** | 168 | /** |
150 | * struct pch_spi_board_data - Holds the SPI device specific details | 169 | * struct pch_spi_board_data - Holds the SPI device specific details |
151 | * @pdev: Pointer to the PCI device | 170 | * @pdev: Pointer to the PCI device |
152 | * @irq_reg_sts: Status of IRQ registration | ||
153 | * @pci_req_sts: Status of pci_request_regions | ||
154 | * @suspend_sts: Status of suspend | 171 | * @suspend_sts: Status of suspend |
155 | * @data: Pointer to SPI channel data structure | 172 | * @num: The number of SPI device instance |
156 | */ | 173 | */ |
157 | struct pch_spi_board_data { | 174 | struct pch_spi_board_data { |
158 | struct pci_dev *pdev; | 175 | struct pci_dev *pdev; |
159 | u8 irq_reg_sts; | ||
160 | u8 pci_req_sts; | ||
161 | u8 suspend_sts; | 176 | u8 suspend_sts; |
162 | struct pch_spi_data *data; | 177 | int num; |
178 | }; | ||
179 | |||
180 | struct pch_pd_dev_save { | ||
181 | int num; | ||
182 | struct platform_device *pd_save[PCH_SPI_MAX_DEV]; | ||
183 | struct pch_spi_board_data *board_dat; | ||
163 | }; | 184 | }; |
164 | 185 | ||
165 | static struct pci_device_id pch_spi_pcidev_id[] = { | 186 | static struct pci_device_id pch_spi_pcidev_id[] = { |
166 | {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_GE_SPI)}, | 187 | { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_GE_SPI), 1, }, |
167 | {0,} | 188 | { PCI_VDEVICE(ROHM, PCI_DEVICE_ID_ML7213_SPI), 2, }, |
189 | { } | ||
168 | }; | 190 | }; |
169 | 191 | ||
170 | /** | 192 | /** |
@@ -283,11 +305,11 @@ static void pch_spi_handler_sub(struct pch_spi_data *data, u32 reg_spsr_val, | |||
283 | static irqreturn_t pch_spi_handler(int irq, void *dev_id) | 305 | static irqreturn_t pch_spi_handler(int irq, void *dev_id) |
284 | { | 306 | { |
285 | u32 reg_spsr_val; | 307 | u32 reg_spsr_val; |
286 | struct pch_spi_data *data; | ||
287 | void __iomem *spsr; | 308 | void __iomem *spsr; |
288 | void __iomem *io_remap_addr; | 309 | void __iomem *io_remap_addr; |
289 | irqreturn_t ret = IRQ_NONE; | 310 | irqreturn_t ret = IRQ_NONE; |
290 | struct pch_spi_board_data *board_dat = dev_id; | 311 | struct pch_spi_data *data = dev_id; |
312 | struct pch_spi_board_data *board_dat = data->board_dat; | ||
291 | 313 | ||
292 | if (board_dat->suspend_sts) { | 314 | if (board_dat->suspend_sts) { |
293 | dev_dbg(&board_dat->pdev->dev, | 315 | dev_dbg(&board_dat->pdev->dev, |
@@ -295,7 +317,6 @@ static irqreturn_t pch_spi_handler(int irq, void *dev_id) | |||
295 | return IRQ_NONE; | 317 | return IRQ_NONE; |
296 | } | 318 | } |
297 | 319 | ||
298 | data = board_dat->data; | ||
299 | io_remap_addr = data->io_remap_addr; | 320 | io_remap_addr = data->io_remap_addr; |
300 | spsr = io_remap_addr + PCH_SPSR; | 321 | spsr = io_remap_addr + PCH_SPSR; |
301 | 322 | ||
@@ -868,117 +889,49 @@ static void pch_spi_process_messages(struct work_struct *pwork) | |||
868 | } while (data->cur_trans != NULL); | 889 | } while (data->cur_trans != NULL); |
869 | } | 890 | } |
870 | 891 | ||
871 | static void pch_spi_free_resources(struct pch_spi_board_data *board_dat) | 892 | static void pch_spi_free_resources(struct pch_spi_board_data *board_dat, |
893 | struct pch_spi_data *data) | ||
872 | { | 894 | { |
873 | dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); | 895 | dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); |
874 | 896 | ||
875 | /* free workqueue */ | 897 | /* free workqueue */ |
876 | if (board_dat->data->wk != NULL) { | 898 | if (data->wk != NULL) { |
877 | destroy_workqueue(board_dat->data->wk); | 899 | destroy_workqueue(data->wk); |
878 | board_dat->data->wk = NULL; | 900 | data->wk = NULL; |
879 | dev_dbg(&board_dat->pdev->dev, | 901 | dev_dbg(&board_dat->pdev->dev, |
880 | "%s destroy_workqueue invoked successfully\n", | 902 | "%s destroy_workqueue invoked successfully\n", |
881 | __func__); | 903 | __func__); |
882 | } | 904 | } |
883 | |||
884 | /* disable interrupts & free IRQ */ | ||
885 | if (board_dat->irq_reg_sts) { | ||
886 | /* disable interrupts */ | ||
887 | pch_spi_setclr_reg(board_dat->data->master, PCH_SPCR, 0, | ||
888 | PCH_ALL); | ||
889 | |||
890 | /* free IRQ */ | ||
891 | free_irq(board_dat->pdev->irq, board_dat); | ||
892 | |||
893 | dev_dbg(&board_dat->pdev->dev, | ||
894 | "%s free_irq invoked successfully\n", __func__); | ||
895 | |||
896 | board_dat->irq_reg_sts = false; | ||
897 | } | ||
898 | |||
899 | /* unmap PCI base address */ | ||
900 | if (board_dat->data->io_remap_addr != 0) { | ||
901 | pci_iounmap(board_dat->pdev, board_dat->data->io_remap_addr); | ||
902 | |||
903 | board_dat->data->io_remap_addr = 0; | ||
904 | |||
905 | dev_dbg(&board_dat->pdev->dev, | ||
906 | "%s pci_iounmap invoked successfully\n", __func__); | ||
907 | } | ||
908 | |||
909 | /* release PCI region */ | ||
910 | if (board_dat->pci_req_sts) { | ||
911 | pci_release_regions(board_dat->pdev); | ||
912 | dev_dbg(&board_dat->pdev->dev, | ||
913 | "%s pci_release_regions invoked successfully\n", | ||
914 | __func__); | ||
915 | board_dat->pci_req_sts = false; | ||
916 | } | ||
917 | } | 905 | } |
918 | 906 | ||
919 | static int pch_spi_get_resources(struct pch_spi_board_data *board_dat) | 907 | static int pch_spi_get_resources(struct pch_spi_board_data *board_dat, |
908 | struct pch_spi_data *data) | ||
920 | { | 909 | { |
921 | void __iomem *io_remap_addr; | 910 | int retval = 0; |
922 | int retval; | 911 | |
923 | dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); | 912 | dev_dbg(&board_dat->pdev->dev, "%s ENTRY\n", __func__); |
924 | 913 | ||
925 | /* create workqueue */ | 914 | /* create workqueue */ |
926 | board_dat->data->wk = create_singlethread_workqueue(KBUILD_MODNAME); | 915 | data->wk = create_singlethread_workqueue(KBUILD_MODNAME); |
927 | if (!board_dat->data->wk) { | 916 | if (!data->wk) { |
928 | dev_err(&board_dat->pdev->dev, | 917 | dev_err(&board_dat->pdev->dev, |
929 | "%s create_singlet hread_workqueue failed\n", __func__); | 918 | "%s create_singlet hread_workqueue failed\n", __func__); |
930 | retval = -EBUSY; | 919 | retval = -EBUSY; |
931 | goto err_return; | 920 | goto err_return; |
932 | } | 921 | } |
933 | 922 | ||
934 | dev_dbg(&board_dat->pdev->dev, | ||
935 | "%s create_singlethread_workqueue success\n", __func__); | ||
936 | |||
937 | retval = pci_request_regions(board_dat->pdev, KBUILD_MODNAME); | ||
938 | if (retval != 0) { | ||
939 | dev_err(&board_dat->pdev->dev, | ||
940 | "%s request_region failed\n", __func__); | ||
941 | goto err_return; | ||
942 | } | ||
943 | |||
944 | board_dat->pci_req_sts = true; | ||
945 | |||
946 | io_remap_addr = pci_iomap(board_dat->pdev, 1, 0); | ||
947 | if (io_remap_addr == 0) { | ||
948 | dev_err(&board_dat->pdev->dev, | ||
949 | "%s pci_iomap failed\n", __func__); | ||
950 | retval = -ENOMEM; | ||
951 | goto err_return; | ||
952 | } | ||
953 | |||
954 | /* calculate base address for all channels */ | ||
955 | board_dat->data->io_remap_addr = io_remap_addr; | ||
956 | |||
957 | /* reset PCH SPI h/w */ | 923 | /* reset PCH SPI h/w */ |
958 | pch_spi_reset(board_dat->data->master); | 924 | pch_spi_reset(data->master); |
959 | dev_dbg(&board_dat->pdev->dev, | 925 | dev_dbg(&board_dat->pdev->dev, |
960 | "%s pch_spi_reset invoked successfully\n", __func__); | 926 | "%s pch_spi_reset invoked successfully\n", __func__); |
961 | 927 | ||
962 | /* register IRQ */ | ||
963 | retval = request_irq(board_dat->pdev->irq, pch_spi_handler, | ||
964 | IRQF_SHARED, KBUILD_MODNAME, board_dat); | ||
965 | if (retval != 0) { | ||
966 | dev_err(&board_dat->pdev->dev, | ||
967 | "%s request_irq failed\n", __func__); | ||
968 | goto err_return; | ||
969 | } | ||
970 | |||
971 | dev_dbg(&board_dat->pdev->dev, "%s request_irq returned=%d\n", | ||
972 | __func__, retval); | ||
973 | |||
974 | board_dat->irq_reg_sts = true; | ||
975 | dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true\n", __func__); | 928 | dev_dbg(&board_dat->pdev->dev, "%s data->irq_reg_sts=true\n", __func__); |
976 | 929 | ||
977 | err_return: | 930 | err_return: |
978 | if (retval != 0) { | 931 | if (retval != 0) { |
979 | dev_err(&board_dat->pdev->dev, | 932 | dev_err(&board_dat->pdev->dev, |
980 | "%s FAIL:invoking pch_spi_free_resources\n", __func__); | 933 | "%s FAIL:invoking pch_spi_free_resources\n", __func__); |
981 | pch_spi_free_resources(board_dat); | 934 | pch_spi_free_resources(board_dat, data); |
982 | } | 935 | } |
983 | 936 | ||
984 | dev_dbg(&board_dat->pdev->dev, "%s Return=%d\n", __func__, retval); | 937 | dev_dbg(&board_dat->pdev->dev, "%s Return=%d\n", __func__, retval); |
@@ -986,255 +939,343 @@ err_return: | |||
986 | return retval; | 939 | return retval; |
987 | } | 940 | } |
988 | 941 | ||
989 | static int pch_spi_probe(struct pci_dev *pdev, const struct pci_device_id *id) | 942 | static int __devinit pch_spi_pd_probe(struct platform_device *plat_dev) |
990 | { | 943 | { |
991 | 944 | int ret; | |
992 | struct spi_master *master; | 945 | struct spi_master *master; |
946 | struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev); | ||
947 | struct pch_spi_data *data; | ||
993 | 948 | ||
994 | struct pch_spi_board_data *board_dat; | 949 | master = spi_alloc_master(&board_dat->pdev->dev, |
995 | int retval; | 950 | sizeof(struct pch_spi_data)); |
996 | 951 | if (!master) { | |
997 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | 952 | dev_err(&plat_dev->dev, "spi_alloc_master[%d] failed.\n", |
998 | 953 | plat_dev->id); | |
999 | /* allocate memory for private data */ | 954 | return -ENOMEM; |
1000 | board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL); | ||
1001 | if (board_dat == NULL) { | ||
1002 | dev_err(&pdev->dev, | ||
1003 | " %s memory allocation for private data failed\n", | ||
1004 | __func__); | ||
1005 | retval = -ENOMEM; | ||
1006 | goto err_kmalloc; | ||
1007 | } | ||
1008 | |||
1009 | dev_dbg(&pdev->dev, | ||
1010 | "%s memory allocation for private data success\n", __func__); | ||
1011 | |||
1012 | /* enable PCI device */ | ||
1013 | retval = pci_enable_device(pdev); | ||
1014 | if (retval != 0) { | ||
1015 | dev_err(&pdev->dev, "%s pci_enable_device FAILED\n", __func__); | ||
1016 | |||
1017 | goto err_pci_en_device; | ||
1018 | } | 955 | } |
1019 | 956 | ||
1020 | dev_dbg(&pdev->dev, "%s pci_enable_device returned=%d\n", | 957 | data = spi_master_get_devdata(master); |
1021 | __func__, retval); | 958 | data->master = master; |
1022 | 959 | ||
1023 | board_dat->pdev = pdev; | 960 | platform_set_drvdata(plat_dev, data); |
1024 | 961 | ||
1025 | /* alllocate memory for SPI master */ | 962 | /* baseaddress + 0x20(offset) */ |
1026 | master = spi_alloc_master(&pdev->dev, sizeof(struct pch_spi_data)); | 963 | data->io_remap_addr = pci_iomap(board_dat->pdev, 1, 0) + |
1027 | if (master == NULL) { | 964 | 0x20 * plat_dev->id; |
1028 | retval = -ENOMEM; | 965 | if (!data->io_remap_addr) { |
1029 | dev_err(&pdev->dev, "%s Fail.\n", __func__); | 966 | dev_err(&plat_dev->dev, "%s pci_iomap failed\n", __func__); |
1030 | goto err_spi_alloc_master; | 967 | ret = -ENOMEM; |
968 | goto err_pci_iomap; | ||
1031 | } | 969 | } |
1032 | 970 | ||
1033 | dev_dbg(&pdev->dev, | 971 | dev_dbg(&plat_dev->dev, "[ch%d] remap_addr=%p\n", |
1034 | "%s spi_alloc_master returned non NULL\n", __func__); | 972 | plat_dev->id, data->io_remap_addr); |
1035 | 973 | ||
1036 | /* initialize members of SPI master */ | 974 | /* initialize members of SPI master */ |
1037 | master->bus_num = -1; | 975 | master->bus_num = -1; |
1038 | master->num_chipselect = PCH_MAX_CS; | 976 | master->num_chipselect = PCH_MAX_CS; |
1039 | master->setup = pch_spi_setup; | 977 | master->setup = pch_spi_setup; |
1040 | master->transfer = pch_spi_transfer; | 978 | master->transfer = pch_spi_transfer; |
1041 | dev_dbg(&pdev->dev, | ||
1042 | "%s transfer member of SPI master initialized\n", __func__); | ||
1043 | 979 | ||
1044 | board_dat->data = spi_master_get_devdata(master); | 980 | data->board_dat = board_dat; |
981 | data->plat_dev = plat_dev; | ||
982 | data->n_curnt_chip = 255; | ||
983 | data->status = STATUS_RUNNING; | ||
984 | data->ch = plat_dev->id; | ||
1045 | 985 | ||
1046 | board_dat->data->master = master; | 986 | INIT_LIST_HEAD(&data->queue); |
1047 | board_dat->data->n_curnt_chip = 255; | 987 | spin_lock_init(&data->lock); |
1048 | board_dat->data->board_dat = board_dat; | 988 | INIT_WORK(&data->work, pch_spi_process_messages); |
1049 | board_dat->data->status = STATUS_RUNNING; | 989 | init_waitqueue_head(&data->wait); |
1050 | 990 | ||
1051 | INIT_LIST_HEAD(&board_dat->data->queue); | 991 | ret = pch_spi_get_resources(board_dat, data); |
1052 | spin_lock_init(&board_dat->data->lock); | 992 | if (ret) { |
1053 | INIT_WORK(&board_dat->data->work, pch_spi_process_messages); | 993 | dev_err(&plat_dev->dev, "%s fail(retval=%d)\n", __func__, ret); |
1054 | init_waitqueue_head(&board_dat->data->wait); | ||
1055 | |||
1056 | /* allocate resources for PCH SPI */ | ||
1057 | retval = pch_spi_get_resources(board_dat); | ||
1058 | if (retval) { | ||
1059 | dev_err(&pdev->dev, "%s fail(retval=%d)\n", __func__, retval); | ||
1060 | goto err_spi_get_resources; | 994 | goto err_spi_get_resources; |
1061 | } | 995 | } |
1062 | 996 | ||
1063 | dev_dbg(&pdev->dev, "%s pch_spi_get_resources returned=%d\n", | 997 | ret = request_irq(board_dat->pdev->irq, pch_spi_handler, |
1064 | __func__, retval); | 998 | IRQF_SHARED, KBUILD_MODNAME, data); |
1065 | 999 | if (ret) { | |
1066 | /* save private data in dev */ | 1000 | dev_err(&plat_dev->dev, |
1067 | pci_set_drvdata(pdev, board_dat); | 1001 | "%s request_irq failed\n", __func__); |
1068 | dev_dbg(&pdev->dev, "%s invoked pci_set_drvdata\n", __func__); | 1002 | goto err_request_irq; |
1003 | } | ||
1004 | data->irq_reg_sts = true; | ||
1069 | 1005 | ||
1070 | /* set master mode */ | ||
1071 | pch_spi_set_master_mode(master); | 1006 | pch_spi_set_master_mode(master); |
1072 | dev_dbg(&pdev->dev, | ||
1073 | "%s invoked pch_spi_set_master_mode\n", __func__); | ||
1074 | 1007 | ||
1075 | /* Register the controller with the SPI core. */ | 1008 | ret = spi_register_master(master); |
1076 | retval = spi_register_master(master); | 1009 | if (ret != 0) { |
1077 | if (retval != 0) { | 1010 | dev_err(&plat_dev->dev, |
1078 | dev_err(&pdev->dev, | ||
1079 | "%s spi_register_master FAILED\n", __func__); | 1011 | "%s spi_register_master FAILED\n", __func__); |
1080 | goto err_spi_reg_master; | 1012 | goto err_spi_register_master; |
1081 | } | 1013 | } |
1082 | 1014 | ||
1083 | dev_dbg(&pdev->dev, "%s spi_register_master returned=%d\n", | ||
1084 | __func__, retval); | ||
1085 | |||
1086 | |||
1087 | return 0; | 1015 | return 0; |
1088 | 1016 | ||
1089 | err_spi_reg_master: | 1017 | err_spi_register_master: |
1090 | spi_unregister_master(master); | 1018 | free_irq(board_dat->pdev->irq, board_dat); |
1019 | err_request_irq: | ||
1020 | pch_spi_free_resources(board_dat, data); | ||
1091 | err_spi_get_resources: | 1021 | err_spi_get_resources: |
1092 | err_spi_alloc_master: | 1022 | pci_iounmap(board_dat->pdev, data->io_remap_addr); |
1023 | err_pci_iomap: | ||
1093 | spi_master_put(master); | 1024 | spi_master_put(master); |
1094 | pci_disable_device(pdev); | 1025 | |
1095 | err_pci_en_device: | 1026 | return ret; |
1096 | kfree(board_dat); | ||
1097 | err_kmalloc: | ||
1098 | return retval; | ||
1099 | } | 1027 | } |
1100 | 1028 | ||
1101 | static void pch_spi_remove(struct pci_dev *pdev) | 1029 | static int __devexit pch_spi_pd_remove(struct platform_device *plat_dev) |
1102 | { | 1030 | { |
1103 | struct pch_spi_board_data *board_dat = pci_get_drvdata(pdev); | 1031 | struct pch_spi_board_data *board_dat = dev_get_platdata(&plat_dev->dev); |
1032 | struct pch_spi_data *data = platform_get_drvdata(plat_dev); | ||
1104 | int count; | 1033 | int count; |
1105 | 1034 | ||
1106 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | 1035 | dev_dbg(&plat_dev->dev, "%s:[ch%d] irq=%d\n", |
1107 | 1036 | __func__, plat_dev->id, board_dat->pdev->irq); | |
1108 | if (!board_dat) { | ||
1109 | dev_err(&pdev->dev, | ||
1110 | "%s pci_get_drvdata returned NULL\n", __func__); | ||
1111 | return; | ||
1112 | } | ||
1113 | |||
1114 | /* check for any pending messages; no action is taken if the queue | 1037 | /* check for any pending messages; no action is taken if the queue |
1115 | * is still full; but at least we tried. Unload anyway */ | 1038 | * is still full; but at least we tried. Unload anyway */ |
1116 | count = 500; | 1039 | count = 500; |
1117 | spin_lock(&board_dat->data->lock); | 1040 | spin_lock(&data->lock); |
1118 | board_dat->data->status = STATUS_EXITING; | 1041 | data->status = STATUS_EXITING; |
1119 | while ((list_empty(&board_dat->data->queue) == 0) && --count) { | 1042 | while ((list_empty(&data->queue) == 0) && --count) { |
1120 | dev_dbg(&board_dat->pdev->dev, "%s :queue not empty\n", | 1043 | dev_dbg(&board_dat->pdev->dev, "%s :queue not empty\n", |
1121 | __func__); | 1044 | __func__); |
1122 | spin_unlock(&board_dat->data->lock); | 1045 | spin_unlock(&data->lock); |
1123 | msleep(PCH_SLEEP_TIME); | 1046 | msleep(PCH_SLEEP_TIME); |
1124 | spin_lock(&board_dat->data->lock); | 1047 | spin_lock(&data->lock); |
1125 | } | 1048 | } |
1126 | spin_unlock(&board_dat->data->lock); | 1049 | spin_unlock(&data->lock); |
1127 | |||
1128 | /* Free resources allocated for PCH SPI */ | ||
1129 | pch_spi_free_resources(board_dat); | ||
1130 | |||
1131 | spi_unregister_master(board_dat->data->master); | ||
1132 | |||
1133 | /* free memory for private data */ | ||
1134 | kfree(board_dat); | ||
1135 | 1050 | ||
1136 | pci_set_drvdata(pdev, NULL); | 1051 | pch_spi_free_resources(board_dat, data); |
1052 | /* disable interrupts & free IRQ */ | ||
1053 | if (data->irq_reg_sts) { | ||
1054 | /* disable interrupts */ | ||
1055 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); | ||
1056 | data->irq_reg_sts = false; | ||
1057 | free_irq(board_dat->pdev->irq, data); | ||
1058 | } | ||
1137 | 1059 | ||
1138 | /* disable PCI device */ | 1060 | pci_iounmap(board_dat->pdev, data->io_remap_addr); |
1139 | pci_disable_device(pdev); | 1061 | spi_unregister_master(data->master); |
1062 | spi_master_put(data->master); | ||
1063 | platform_set_drvdata(plat_dev, NULL); | ||
1140 | 1064 | ||
1141 | dev_dbg(&pdev->dev, "%s invoked pci_disable_device\n", __func__); | 1065 | return 0; |
1142 | } | 1066 | } |
1143 | |||
1144 | #ifdef CONFIG_PM | 1067 | #ifdef CONFIG_PM |
1145 | static int pch_spi_suspend(struct pci_dev *pdev, pm_message_t state) | 1068 | static int pch_spi_pd_suspend(struct platform_device *pd_dev, |
1069 | pm_message_t state) | ||
1146 | { | 1070 | { |
1147 | u8 count; | 1071 | u8 count; |
1148 | int retval; | 1072 | struct pch_spi_board_data *board_dat = dev_get_platdata(&pd_dev->dev); |
1073 | struct pch_spi_data *data = platform_get_drvdata(pd_dev); | ||
1149 | 1074 | ||
1150 | struct pch_spi_board_data *board_dat = pci_get_drvdata(pdev); | 1075 | dev_dbg(&pd_dev->dev, "%s ENTRY\n", __func__); |
1151 | |||
1152 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | ||
1153 | 1076 | ||
1154 | if (!board_dat) { | 1077 | if (!board_dat) { |
1155 | dev_err(&pdev->dev, | 1078 | dev_err(&pd_dev->dev, |
1156 | "%s pci_get_drvdata returned NULL\n", __func__); | 1079 | "%s pci_get_drvdata returned NULL\n", __func__); |
1157 | return -EFAULT; | 1080 | return -EFAULT; |
1158 | } | 1081 | } |
1159 | 1082 | ||
1160 | retval = 0; | ||
1161 | board_dat->suspend_sts = true; | ||
1162 | |||
1163 | /* check if the current message is processed: | 1083 | /* check if the current message is processed: |
1164 | Only after thats done the transfer will be suspended */ | 1084 | Only after thats done the transfer will be suspended */ |
1165 | count = 255; | 1085 | count = 255; |
1166 | while ((--count) > 0) { | 1086 | while ((--count) > 0) |
1167 | if (!(board_dat->data->bcurrent_msg_processing)) { | 1087 | if (!(data->bcurrent_msg_processing)) { |
1168 | dev_dbg(&pdev->dev, "%s board_dat->data->bCurrent_" | ||
1169 | "msg_processing = false\n", __func__); | ||
1170 | break; | 1088 | break; |
1171 | } else { | ||
1172 | dev_dbg(&pdev->dev, "%s board_dat->data->bCurrent_msg_" | ||
1173 | "processing = true\n", __func__); | ||
1174 | } | ||
1175 | msleep(PCH_SLEEP_TIME); | 1089 | msleep(PCH_SLEEP_TIME); |
1176 | } | 1090 | } |
1177 | 1091 | ||
1178 | /* Free IRQ */ | 1092 | /* Free IRQ */ |
1179 | if (board_dat->irq_reg_sts) { | 1093 | if (data->irq_reg_sts) { |
1180 | /* disable all interrupts */ | 1094 | /* disable all interrupts */ |
1181 | pch_spi_setclr_reg(board_dat->data->master, PCH_SPCR, 0, | 1095 | pch_spi_setclr_reg(data->master, PCH_SPCR, 0, PCH_ALL); |
1182 | PCH_ALL); | 1096 | pch_spi_reset(data->master); |
1183 | pch_spi_reset(board_dat->data->master); | 1097 | free_irq(board_dat->pdev->irq, data); |
1184 | |||
1185 | free_irq(board_dat->pdev->irq, board_dat); | ||
1186 | 1098 | ||
1187 | board_dat->irq_reg_sts = false; | 1099 | data->irq_reg_sts = false; |
1188 | dev_dbg(&pdev->dev, | 1100 | dev_dbg(&pd_dev->dev, |
1189 | "%s free_irq invoked successfully.\n", __func__); | 1101 | "%s free_irq invoked successfully.\n", __func__); |
1190 | } | 1102 | } |
1191 | 1103 | ||
1104 | return 0; | ||
1105 | } | ||
1106 | |||
1107 | static int pch_spi_pd_resume(struct platform_device *pd_dev) | ||
1108 | { | ||
1109 | struct pch_spi_board_data *board_dat = dev_get_platdata(&pd_dev->dev); | ||
1110 | struct pch_spi_data *data = platform_get_drvdata(pd_dev); | ||
1111 | int retval; | ||
1112 | |||
1113 | if (!board_dat) { | ||
1114 | dev_err(&pd_dev->dev, | ||
1115 | "%s pci_get_drvdata returned NULL\n", __func__); | ||
1116 | return -EFAULT; | ||
1117 | } | ||
1118 | |||
1119 | if (!data->irq_reg_sts) { | ||
1120 | /* register IRQ */ | ||
1121 | retval = request_irq(board_dat->pdev->irq, pch_spi_handler, | ||
1122 | IRQF_SHARED, KBUILD_MODNAME, data); | ||
1123 | if (retval < 0) { | ||
1124 | dev_err(&pd_dev->dev, | ||
1125 | "%s request_irq failed\n", __func__); | ||
1126 | return retval; | ||
1127 | } | ||
1128 | |||
1129 | /* reset PCH SPI h/w */ | ||
1130 | pch_spi_reset(data->master); | ||
1131 | pch_spi_set_master_mode(data->master); | ||
1132 | data->irq_reg_sts = true; | ||
1133 | } | ||
1134 | return 0; | ||
1135 | } | ||
1136 | #else | ||
1137 | #define pch_spi_pd_suspend NULL | ||
1138 | #define pch_spi_pd_resume NULL | ||
1139 | #endif | ||
1140 | |||
1141 | static struct platform_driver pch_spi_pd_driver = { | ||
1142 | .driver = { | ||
1143 | .name = "pch-spi", | ||
1144 | .owner = THIS_MODULE, | ||
1145 | }, | ||
1146 | .probe = pch_spi_pd_probe, | ||
1147 | .remove = __devexit_p(pch_spi_pd_remove), | ||
1148 | .suspend = pch_spi_pd_suspend, | ||
1149 | .resume = pch_spi_pd_resume | ||
1150 | }; | ||
1151 | |||
1152 | static int __devinit pch_spi_probe(struct pci_dev *pdev, | ||
1153 | const struct pci_device_id *id) | ||
1154 | { | ||
1155 | struct pch_spi_board_data *board_dat; | ||
1156 | struct platform_device *pd_dev = NULL; | ||
1157 | int retval; | ||
1158 | int i; | ||
1159 | struct pch_pd_dev_save *pd_dev_save; | ||
1160 | |||
1161 | pd_dev_save = kzalloc(sizeof(struct pch_pd_dev_save), GFP_KERNEL); | ||
1162 | if (!pd_dev_save) { | ||
1163 | dev_err(&pdev->dev, "%s Can't allocate pd_dev_sav\n", __func__); | ||
1164 | return -ENOMEM; | ||
1165 | } | ||
1166 | |||
1167 | board_dat = kzalloc(sizeof(struct pch_spi_board_data), GFP_KERNEL); | ||
1168 | if (!board_dat) { | ||
1169 | dev_err(&pdev->dev, "%s Can't allocate board_dat\n", __func__); | ||
1170 | retval = -ENOMEM; | ||
1171 | goto err_no_mem; | ||
1172 | } | ||
1173 | |||
1174 | retval = pci_request_regions(pdev, KBUILD_MODNAME); | ||
1175 | if (retval) { | ||
1176 | dev_err(&pdev->dev, "%s request_region failed\n", __func__); | ||
1177 | goto pci_request_regions; | ||
1178 | } | ||
1179 | |||
1180 | board_dat->pdev = pdev; | ||
1181 | board_dat->num = id->driver_data; | ||
1182 | pd_dev_save->num = id->driver_data; | ||
1183 | pd_dev_save->board_dat = board_dat; | ||
1184 | |||
1185 | retval = pci_enable_device(pdev); | ||
1186 | if (retval) { | ||
1187 | dev_err(&pdev->dev, "%s pci_enable_device failed\n", __func__); | ||
1188 | goto pci_enable_device; | ||
1189 | } | ||
1190 | |||
1191 | for (i = 0; i < board_dat->num; i++) { | ||
1192 | pd_dev = platform_device_alloc("pch-spi", i); | ||
1193 | if (!pd_dev) { | ||
1194 | dev_err(&pdev->dev, "platform_device_alloc failed\n"); | ||
1195 | goto err_platform_device; | ||
1196 | } | ||
1197 | pd_dev_save->pd_save[i] = pd_dev; | ||
1198 | pd_dev->dev.parent = &pdev->dev; | ||
1199 | |||
1200 | retval = platform_device_add_data(pd_dev, board_dat, | ||
1201 | sizeof(*board_dat)); | ||
1202 | if (retval) { | ||
1203 | dev_err(&pdev->dev, | ||
1204 | "platform_device_add_data failed\n"); | ||
1205 | platform_device_put(pd_dev); | ||
1206 | goto err_platform_device; | ||
1207 | } | ||
1208 | |||
1209 | retval = platform_device_add(pd_dev); | ||
1210 | if (retval) { | ||
1211 | dev_err(&pdev->dev, "platform_device_add failed\n"); | ||
1212 | platform_device_put(pd_dev); | ||
1213 | goto err_platform_device; | ||
1214 | } | ||
1215 | } | ||
1216 | |||
1217 | pci_set_drvdata(pdev, pd_dev_save); | ||
1218 | |||
1219 | return 0; | ||
1220 | |||
1221 | err_platform_device: | ||
1222 | pci_disable_device(pdev); | ||
1223 | pci_enable_device: | ||
1224 | pci_release_regions(pdev); | ||
1225 | pci_request_regions: | ||
1226 | kfree(board_dat); | ||
1227 | err_no_mem: | ||
1228 | kfree(pd_dev_save); | ||
1229 | |||
1230 | return retval; | ||
1231 | } | ||
1232 | |||
1233 | static void __devexit pch_spi_remove(struct pci_dev *pdev) | ||
1234 | { | ||
1235 | int i; | ||
1236 | struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev); | ||
1237 | |||
1238 | dev_dbg(&pdev->dev, "%s ENTRY:pdev=%p\n", __func__, pdev); | ||
1239 | |||
1240 | for (i = 0; i < pd_dev_save->num; i++) | ||
1241 | platform_device_unregister(pd_dev_save->pd_save[i]); | ||
1242 | |||
1243 | pci_disable_device(pdev); | ||
1244 | pci_release_regions(pdev); | ||
1245 | kfree(pd_dev_save->board_dat); | ||
1246 | kfree(pd_dev_save); | ||
1247 | } | ||
1248 | |||
1249 | #ifdef CONFIG_PM | ||
1250 | static int pch_spi_suspend(struct pci_dev *pdev, pm_message_t state) | ||
1251 | { | ||
1252 | int retval; | ||
1253 | struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev); | ||
1254 | |||
1255 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | ||
1256 | |||
1257 | pd_dev_save->board_dat->suspend_sts = true; | ||
1258 | |||
1192 | /* save config space */ | 1259 | /* save config space */ |
1193 | retval = pci_save_state(pdev); | 1260 | retval = pci_save_state(pdev); |
1194 | |||
1195 | if (retval == 0) { | 1261 | if (retval == 0) { |
1196 | dev_dbg(&pdev->dev, "%s pci_save_state returned=%d\n", | ||
1197 | __func__, retval); | ||
1198 | /* disable PM notifications */ | ||
1199 | pci_enable_wake(pdev, PCI_D3hot, 0); | 1262 | pci_enable_wake(pdev, PCI_D3hot, 0); |
1200 | dev_dbg(&pdev->dev, | ||
1201 | "%s pci_enable_wake invoked successfully\n", __func__); | ||
1202 | /* disable PCI device */ | ||
1203 | pci_disable_device(pdev); | 1263 | pci_disable_device(pdev); |
1204 | dev_dbg(&pdev->dev, | ||
1205 | "%s pci_disable_device invoked successfully\n", | ||
1206 | __func__); | ||
1207 | /* move device to D3hot state */ | ||
1208 | pci_set_power_state(pdev, PCI_D3hot); | 1264 | pci_set_power_state(pdev, PCI_D3hot); |
1209 | dev_dbg(&pdev->dev, | ||
1210 | "%s pci_set_power_state invoked successfully\n", | ||
1211 | __func__); | ||
1212 | } else { | 1265 | } else { |
1213 | dev_err(&pdev->dev, "%s pci_save_state failed\n", __func__); | 1266 | dev_err(&pdev->dev, "%s pci_save_state failed\n", __func__); |
1214 | } | 1267 | } |
1215 | 1268 | ||
1216 | dev_dbg(&pdev->dev, "%s return=%d\n", __func__, retval); | ||
1217 | |||
1218 | return retval; | 1269 | return retval; |
1219 | } | 1270 | } |
1220 | 1271 | ||
1221 | static int pch_spi_resume(struct pci_dev *pdev) | 1272 | static int pch_spi_resume(struct pci_dev *pdev) |
1222 | { | 1273 | { |
1223 | int retval; | 1274 | int retval; |
1224 | 1275 | struct pch_pd_dev_save *pd_dev_save = pci_get_drvdata(pdev); | |
1225 | struct pch_spi_board_data *board = pci_get_drvdata(pdev); | ||
1226 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); | 1276 | dev_dbg(&pdev->dev, "%s ENTRY\n", __func__); |
1227 | 1277 | ||
1228 | if (!board) { | ||
1229 | dev_err(&pdev->dev, | ||
1230 | "%s pci_get_drvdata returned NULL\n", __func__); | ||
1231 | return -EFAULT; | ||
1232 | } | ||
1233 | |||
1234 | /* move device to DO power state */ | ||
1235 | pci_set_power_state(pdev, PCI_D0); | 1278 | pci_set_power_state(pdev, PCI_D0); |
1236 | |||
1237 | /* restore state */ | ||
1238 | pci_restore_state(pdev); | 1279 | pci_restore_state(pdev); |
1239 | 1280 | ||
1240 | retval = pci_enable_device(pdev); | 1281 | retval = pci_enable_device(pdev); |
@@ -1242,34 +1283,12 @@ static int pch_spi_resume(struct pci_dev *pdev) | |||
1242 | dev_err(&pdev->dev, | 1283 | dev_err(&pdev->dev, |
1243 | "%s pci_enable_device failed\n", __func__); | 1284 | "%s pci_enable_device failed\n", __func__); |
1244 | } else { | 1285 | } else { |
1245 | /* disable PM notifications */ | ||
1246 | pci_enable_wake(pdev, PCI_D3hot, 0); | 1286 | pci_enable_wake(pdev, PCI_D3hot, 0); |
1247 | 1287 | ||
1248 | /* register IRQ handler */ | 1288 | /* set suspend status to false */ |
1249 | if (!board->irq_reg_sts) { | 1289 | pd_dev_save->board_dat->suspend_sts = false; |
1250 | /* register IRQ */ | ||
1251 | retval = request_irq(board->pdev->irq, pch_spi_handler, | ||
1252 | IRQF_SHARED, KBUILD_MODNAME, | ||
1253 | board); | ||
1254 | if (retval < 0) { | ||
1255 | dev_err(&pdev->dev, | ||
1256 | "%s request_irq failed\n", __func__); | ||
1257 | return retval; | ||
1258 | } | ||
1259 | board->irq_reg_sts = true; | ||
1260 | |||
1261 | /* reset PCH SPI h/w */ | ||
1262 | pch_spi_reset(board->data->master); | ||
1263 | pch_spi_set_master_mode(board->data->master); | ||
1264 | |||
1265 | /* set suspend status to false */ | ||
1266 | board->suspend_sts = false; | ||
1267 | |||
1268 | } | ||
1269 | } | 1290 | } |
1270 | 1291 | ||
1271 | dev_dbg(&pdev->dev, "%s returning=%d\n", __func__, retval); | ||
1272 | |||
1273 | return retval; | 1292 | return retval; |
1274 | } | 1293 | } |
1275 | #else | 1294 | #else |
@@ -1289,15 +1308,25 @@ static struct pci_driver pch_spi_pcidev = { | |||
1289 | 1308 | ||
1290 | static int __init pch_spi_init(void) | 1309 | static int __init pch_spi_init(void) |
1291 | { | 1310 | { |
1292 | return pci_register_driver(&pch_spi_pcidev); | 1311 | int ret; |
1312 | ret = platform_driver_register(&pch_spi_pd_driver); | ||
1313 | if (ret) | ||
1314 | return ret; | ||
1315 | |||
1316 | ret = pci_register_driver(&pch_spi_pcidev); | ||
1317 | if (ret) | ||
1318 | return ret; | ||
1319 | |||
1320 | return 0; | ||
1293 | } | 1321 | } |
1294 | module_init(pch_spi_init); | 1322 | module_init(pch_spi_init); |
1295 | 1323 | ||
1296 | static void __exit pch_spi_exit(void) | 1324 | static void __exit pch_spi_exit(void) |
1297 | { | 1325 | { |
1298 | pci_unregister_driver(&pch_spi_pcidev); | 1326 | pci_unregister_driver(&pch_spi_pcidev); |
1327 | platform_driver_unregister(&pch_spi_pd_driver); | ||
1299 | } | 1328 | } |
1300 | module_exit(pch_spi_exit); | 1329 | module_exit(pch_spi_exit); |
1301 | 1330 | ||
1302 | MODULE_LICENSE("GPL"); | 1331 | MODULE_LICENSE("GPL"); |
1303 | MODULE_DESCRIPTION("Topcliff PCH SPI PCI Driver"); | 1332 | MODULE_DESCRIPTION("Intel EG20T PCH/OKI SEMICONDUCTOR ML7213 IOH SPI Driver"); |