]>
Commit | Line | Data |
---|---|---|
c942fddf | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
52b1eaf4 KS |
2 | /* |
3 | * netup_unidvb_spi.c | |
4 | * | |
5 | * Internal SPI driver for NetUP Universal Dual DVB-CI | |
6 | * | |
7 | * Copyright (C) 2014 NetUP Inc. | |
8 | * Copyright (C) 2014 Sergey Kozlov <serjk@netup.ru> | |
9 | * Copyright (C) 2014 Abylay Ospan <aospan@netup.ru> | |
52b1eaf4 KS |
10 | */ |
11 | ||
12 | #include "netup_unidvb.h" | |
13 | #include <linux/spi/spi.h> | |
14 | #include <linux/spi/flash.h> | |
15 | #include <linux/mtd/partitions.h> | |
16 | #include <mtd/mtd-abi.h> | |
17 | ||
18 | #define NETUP_SPI_CTRL_IRQ 0x1000 | |
19 | #define NETUP_SPI_CTRL_IMASK 0x2000 | |
20 | #define NETUP_SPI_CTRL_START 0x8000 | |
21 | #define NETUP_SPI_CTRL_LAST_CS 0x4000 | |
22 | ||
23 | #define NETUP_SPI_TIMEOUT 6000 | |
24 | ||
25 | enum netup_spi_state { | |
26 | SPI_STATE_START, | |
27 | SPI_STATE_DONE, | |
28 | }; | |
29 | ||
30 | struct netup_spi_regs { | |
31 | __u8 data[1024]; | |
32 | __le16 control_stat; | |
33 | __le16 clock_divider; | |
34 | } __packed __aligned(1); | |
35 | ||
36 | struct netup_spi { | |
37 | struct device *dev; | |
38 | struct spi_master *master; | |
d91b1d91 | 39 | struct netup_spi_regs __iomem *regs; |
52b1eaf4 KS |
40 | u8 __iomem *mmio; |
41 | spinlock_t lock; | |
42 | wait_queue_head_t waitq; | |
43 | enum netup_spi_state state; | |
44 | }; | |
45 | ||
46 | static char netup_spi_name[64] = "fpga"; | |
47 | ||
48 | static struct mtd_partition netup_spi_flash_partitions = { | |
49 | .name = netup_spi_name, | |
50 | .size = 0x1000000, /* 16MB */ | |
51 | .offset = 0, | |
52 | .mask_flags = MTD_CAP_ROM | |
53 | }; | |
54 | ||
55 | static struct flash_platform_data spi_flash_data = { | |
56 | .name = "netup0_m25p128", | |
57 | .parts = &netup_spi_flash_partitions, | |
58 | .nr_parts = 1, | |
59 | }; | |
60 | ||
61 | static struct spi_board_info netup_spi_board = { | |
62 | .modalias = "m25p128", | |
63 | .max_speed_hz = 11000000, | |
64 | .chip_select = 0, | |
65 | .mode = SPI_MODE_0, | |
66 | .platform_data = &spi_flash_data, | |
67 | }; | |
68 | ||
69 | irqreturn_t netup_spi_interrupt(struct netup_spi *spi) | |
70 | { | |
71 | u16 reg; | |
72 | unsigned long flags; | |
73 | ||
9d2b064c | 74 | if (!spi) |
52b1eaf4 | 75 | return IRQ_NONE; |
9d2b064c | 76 | |
52b1eaf4 KS |
77 | spin_lock_irqsave(&spi->lock, flags); |
78 | reg = readw(&spi->regs->control_stat); | |
79 | if (!(reg & NETUP_SPI_CTRL_IRQ)) { | |
80 | spin_unlock_irqrestore(&spi->lock, flags); | |
81 | dev_dbg(&spi->master->dev, | |
82 | "%s(): not mine interrupt\n", __func__); | |
83 | return IRQ_NONE; | |
84 | } | |
85 | writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat); | |
86 | reg = readw(&spi->regs->control_stat); | |
87 | writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat); | |
88 | spi->state = SPI_STATE_DONE; | |
89 | wake_up(&spi->waitq); | |
90 | spin_unlock_irqrestore(&spi->lock, flags); | |
91 | dev_dbg(&spi->master->dev, | |
92 | "%s(): SPI interrupt handled\n", __func__); | |
93 | return IRQ_HANDLED; | |
94 | } | |
95 | ||
96 | static int netup_spi_transfer(struct spi_master *master, | |
97 | struct spi_message *msg) | |
98 | { | |
99 | struct netup_spi *spi = spi_master_get_devdata(master); | |
100 | struct spi_transfer *t; | |
101 | int result = 0; | |
102 | u32 tr_size; | |
103 | ||
104 | /* reset CS */ | |
105 | writew(NETUP_SPI_CTRL_LAST_CS, &spi->regs->control_stat); | |
106 | writew(0, &spi->regs->control_stat); | |
107 | list_for_each_entry(t, &msg->transfers, transfer_list) { | |
108 | tr_size = t->len; | |
109 | while (tr_size) { | |
110 | u32 frag_offset = t->len - tr_size; | |
111 | u32 frag_size = (tr_size > sizeof(spi->regs->data)) ? | |
112 | sizeof(spi->regs->data) : tr_size; | |
113 | int frag_last = 0; | |
114 | ||
115 | if (list_is_last(&t->transfer_list, | |
116 | &msg->transfers) && | |
117 | frag_offset + frag_size == t->len) { | |
118 | frag_last = 1; | |
119 | } | |
120 | if (t->tx_buf) { | |
121 | memcpy_toio(spi->regs->data, | |
122 | t->tx_buf + frag_offset, | |
123 | frag_size); | |
124 | } else { | |
125 | memset_io(spi->regs->data, | |
126 | 0, frag_size); | |
127 | } | |
128 | spi->state = SPI_STATE_START; | |
129 | writew((frag_size & 0x3ff) | | |
130 | NETUP_SPI_CTRL_IMASK | | |
131 | NETUP_SPI_CTRL_START | | |
132 | (frag_last ? NETUP_SPI_CTRL_LAST_CS : 0), | |
133 | &spi->regs->control_stat); | |
134 | dev_dbg(&spi->master->dev, | |
135 | "%s(): control_stat 0x%04x\n", | |
136 | __func__, readw(&spi->regs->control_stat)); | |
137 | wait_event_timeout(spi->waitq, | |
138 | spi->state != SPI_STATE_START, | |
139 | msecs_to_jiffies(NETUP_SPI_TIMEOUT)); | |
140 | if (spi->state == SPI_STATE_DONE) { | |
141 | if (t->rx_buf) { | |
142 | memcpy_fromio(t->rx_buf + frag_offset, | |
143 | spi->regs->data, frag_size); | |
144 | } | |
145 | } else { | |
146 | if (spi->state == SPI_STATE_START) { | |
147 | dev_dbg(&spi->master->dev, | |
148 | "%s(): transfer timeout\n", | |
149 | __func__); | |
150 | } else { | |
151 | dev_dbg(&spi->master->dev, | |
152 | "%s(): invalid state %d\n", | |
153 | __func__, spi->state); | |
154 | } | |
155 | result = -EIO; | |
156 | goto done; | |
157 | } | |
158 | tr_size -= frag_size; | |
159 | msg->actual_length += frag_size; | |
160 | } | |
161 | } | |
162 | done: | |
163 | msg->status = result; | |
164 | spi_finalize_current_message(master); | |
165 | return result; | |
166 | } | |
167 | ||
168 | static int netup_spi_setup(struct spi_device *spi) | |
169 | { | |
170 | return 0; | |
171 | } | |
172 | ||
173 | int netup_spi_init(struct netup_unidvb_dev *ndev) | |
174 | { | |
175 | struct spi_master *master; | |
176 | struct netup_spi *nspi; | |
177 | ||
178 | master = spi_alloc_master(&ndev->pci_dev->dev, | |
179 | sizeof(struct netup_spi)); | |
180 | if (!master) { | |
181 | dev_err(&ndev->pci_dev->dev, | |
182 | "%s(): unable to alloc SPI master\n", __func__); | |
183 | return -EINVAL; | |
184 | } | |
185 | nspi = spi_master_get_devdata(master); | |
186 | master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST; | |
187 | master->bus_num = -1; | |
188 | master->num_chipselect = 1; | |
189 | master->transfer_one_message = netup_spi_transfer; | |
190 | master->setup = netup_spi_setup; | |
191 | spin_lock_init(&nspi->lock); | |
192 | init_waitqueue_head(&nspi->waitq); | |
193 | nspi->master = master; | |
d91b1d91 | 194 | nspi->regs = (struct netup_spi_regs __iomem *)(ndev->bmmio0 + 0x4000); |
52b1eaf4 KS |
195 | writew(2, &nspi->regs->clock_divider); |
196 | writew(NETUP_UNIDVB_IRQ_SPI, ndev->bmmio0 + REG_IMASK_SET); | |
197 | ndev->spi = nspi; | |
198 | if (spi_register_master(master)) { | |
199 | ndev->spi = NULL; | |
200 | dev_err(&ndev->pci_dev->dev, | |
201 | "%s(): unable to register SPI bus\n", __func__); | |
202 | return -EINVAL; | |
203 | } | |
204 | snprintf(netup_spi_name, | |
205 | sizeof(netup_spi_name), | |
206 | "fpga_%02x:%02x.%01x", | |
207 | ndev->pci_bus, | |
208 | ndev->pci_slot, | |
209 | ndev->pci_func); | |
210 | if (!spi_new_device(master, &netup_spi_board)) { | |
211 | ndev->spi = NULL; | |
212 | dev_err(&ndev->pci_dev->dev, | |
213 | "%s(): unable to create SPI device\n", __func__); | |
214 | return -EINVAL; | |
215 | } | |
216 | dev_dbg(&ndev->pci_dev->dev, "%s(): SPI init OK\n", __func__); | |
217 | return 0; | |
218 | } | |
219 | ||
220 | void netup_spi_release(struct netup_unidvb_dev *ndev) | |
221 | { | |
222 | u16 reg; | |
223 | unsigned long flags; | |
224 | struct netup_spi *spi = ndev->spi; | |
225 | ||
9d2b064c | 226 | if (!spi) |
52b1eaf4 | 227 | return; |
9d2b064c | 228 | |
52b1eaf4 KS |
229 | spin_lock_irqsave(&spi->lock, flags); |
230 | reg = readw(&spi->regs->control_stat); | |
231 | writew(reg | NETUP_SPI_CTRL_IRQ, &spi->regs->control_stat); | |
232 | reg = readw(&spi->regs->control_stat); | |
233 | writew(reg & ~NETUP_SPI_CTRL_IMASK, &spi->regs->control_stat); | |
234 | spin_unlock_irqrestore(&spi->lock, flags); | |
235 | spi_unregister_master(spi->master); | |
236 | ndev->spi = NULL; | |
237 | } | |
238 | ||
239 |