aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/spi')
-rw-r--r--drivers/spi/spi-s3c64xx.c140
1 files changed, 76 insertions, 64 deletions
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 24f49032ec35..019a7163572f 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -131,6 +131,12 @@
131#define RXBUSY (1<<2) 131#define RXBUSY (1<<2)
132#define TXBUSY (1<<3) 132#define TXBUSY (1<<3)
133 133
134struct s3c64xx_spi_dma_data {
135 unsigned ch;
136 enum dma_data_direction direction;
137 enum dma_ch dmach;
138};
139
134/** 140/**
135 * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver. 141 * struct s3c64xx_spi_driver_data - Runtime info holder for SPI driver.
136 * @clk: Pointer to the spi clock. 142 * @clk: Pointer to the spi clock.
@@ -164,15 +170,13 @@ struct s3c64xx_spi_driver_data {
164 struct work_struct work; 170 struct work_struct work;
165 struct list_head queue; 171 struct list_head queue;
166 spinlock_t lock; 172 spinlock_t lock;
167 enum dma_ch rx_dmach;
168 enum dma_ch tx_dmach;
169 unsigned long sfr_start; 173 unsigned long sfr_start;
170 struct completion xfer_completion; 174 struct completion xfer_completion;
171 unsigned state; 175 unsigned state;
172 unsigned cur_mode, cur_bpw; 176 unsigned cur_mode, cur_bpw;
173 unsigned cur_speed; 177 unsigned cur_speed;
174 unsigned rx_ch; 178 struct s3c64xx_spi_dma_data rx_dma;
175 unsigned tx_ch; 179 struct s3c64xx_spi_dma_data tx_dma;
176 struct samsung_dma_ops *ops; 180 struct samsung_dma_ops *ops;
177}; 181};
178 182
@@ -229,36 +233,76 @@ static void flush_fifo(struct s3c64xx_spi_driver_data *sdd)
229 writel(val, regs + S3C64XX_SPI_CH_CFG); 233 writel(val, regs + S3C64XX_SPI_CH_CFG);
230} 234}
231 235
232static void s3c64xx_spi_dma_rxcb(void *data) 236static void s3c64xx_spi_dmacb(void *data)
233{ 237{
234 struct s3c64xx_spi_driver_data *sdd 238 struct s3c64xx_spi_driver_data *sdd;
235 = (struct s3c64xx_spi_driver_data *)data; 239 struct s3c64xx_spi_dma_data *dma = data;
236 unsigned long flags; 240 unsigned long flags;
237 241
242 if (dma->direction == DMA_FROM_DEVICE)
243 sdd = container_of(data,
244 struct s3c64xx_spi_driver_data, rx_dma);
245 else
246 sdd = container_of(data,
247 struct s3c64xx_spi_driver_data, tx_dma);
248
238 spin_lock_irqsave(&sdd->lock, flags); 249 spin_lock_irqsave(&sdd->lock, flags);
239 250
240 sdd->state &= ~RXBUSY; 251 if (dma->direction == DMA_FROM_DEVICE) {
241 /* If the other done */ 252 sdd->state &= ~RXBUSY;
242 if (!(sdd->state & TXBUSY)) 253 if (!(sdd->state & TXBUSY))
243 complete(&sdd->xfer_completion); 254 complete(&sdd->xfer_completion);
255 } else {
256 sdd->state &= ~TXBUSY;
257 if (!(sdd->state & RXBUSY))
258 complete(&sdd->xfer_completion);
259 }
244 260
245 spin_unlock_irqrestore(&sdd->lock, flags); 261 spin_unlock_irqrestore(&sdd->lock, flags);
246} 262}
247 263
248static void s3c64xx_spi_dma_txcb(void *data) 264static void prepare_dma(struct s3c64xx_spi_dma_data *dma,
265 unsigned len, dma_addr_t buf)
249{ 266{
250 struct s3c64xx_spi_driver_data *sdd 267 struct s3c64xx_spi_driver_data *sdd;
251 = (struct s3c64xx_spi_driver_data *)data; 268 struct samsung_dma_prep_info info;
252 unsigned long flags;
253 269
254 spin_lock_irqsave(&sdd->lock, flags); 270 if (dma->direction == DMA_FROM_DEVICE)
271 sdd = container_of((void *)dma,
272 struct s3c64xx_spi_driver_data, rx_dma);
273 else
274 sdd = container_of((void *)dma,
275 struct s3c64xx_spi_driver_data, tx_dma);
255 276
256 sdd->state &= ~TXBUSY; 277 info.cap = DMA_SLAVE;
257 /* If the other done */ 278 info.len = len;
258 if (!(sdd->state & RXBUSY)) 279 info.fp = s3c64xx_spi_dmacb;
259 complete(&sdd->xfer_completion); 280 info.fp_param = dma;
281 info.direction = dma->direction;
282 info.buf = buf;
283
284 sdd->ops->prepare(dma->ch, &info);
285 sdd->ops->trigger(dma->ch);
286}
260 287
261 spin_unlock_irqrestore(&sdd->lock, flags); 288static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
289{
290 struct samsung_dma_info info;
291
292 sdd->ops = samsung_dma_get_ops();
293
294 info.cap = DMA_SLAVE;
295 info.client = &s3c64xx_spi_dma_client;
296 info.width = sdd->cur_bpw / 8;
297
298 info.direction = sdd->rx_dma.direction;
299 info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
300 sdd->rx_dma.ch = sdd->ops->request(sdd->rx_dma.dmach, &info);
301 info.direction = sdd->tx_dma.direction;
302 info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
303 sdd->tx_dma.ch = sdd->ops->request(sdd->tx_dma.dmach, &info);
304
305 return 1;
262} 306}
263 307
264static void enable_datapath(struct s3c64xx_spi_driver_data *sdd, 308static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
@@ -268,7 +312,6 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
268 struct s3c64xx_spi_info *sci = sdd->cntrlr_info; 312 struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
269 void __iomem *regs = sdd->regs; 313 void __iomem *regs = sdd->regs;
270 u32 modecfg, chcfg; 314 u32 modecfg, chcfg;
271 struct samsung_dma_prep_info info;
272 315
273 modecfg = readl(regs + S3C64XX_SPI_MODE_CFG); 316 modecfg = readl(regs + S3C64XX_SPI_MODE_CFG);
274 modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON); 317 modecfg &= ~(S3C64XX_SPI_MODE_TXDMA_ON | S3C64XX_SPI_MODE_RXDMA_ON);
@@ -294,14 +337,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
294 chcfg |= S3C64XX_SPI_CH_TXCH_ON; 337 chcfg |= S3C64XX_SPI_CH_TXCH_ON;
295 if (dma_mode) { 338 if (dma_mode) {
296 modecfg |= S3C64XX_SPI_MODE_TXDMA_ON; 339 modecfg |= S3C64XX_SPI_MODE_TXDMA_ON;
297 info.cap = DMA_SLAVE; 340 prepare_dma(&sdd->tx_dma, xfer->len, xfer->tx_dma);
298 info.direction = DMA_TO_DEVICE;
299 info.buf = xfer->tx_dma;
300 info.len = xfer->len;
301 info.fp = s3c64xx_spi_dma_txcb;
302 info.fp_param = sdd;
303 sdd->ops->prepare(sdd->tx_ch, &info);
304 sdd->ops->trigger(sdd->tx_ch);
305 } else { 341 } else {
306 switch (sdd->cur_bpw) { 342 switch (sdd->cur_bpw) {
307 case 32: 343 case 32:
@@ -333,14 +369,7 @@ static void enable_datapath(struct s3c64xx_spi_driver_data *sdd,
333 writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff) 369 writel(((xfer->len * 8 / sdd->cur_bpw) & 0xffff)
334 | S3C64XX_SPI_PACKET_CNT_EN, 370 | S3C64XX_SPI_PACKET_CNT_EN,
335 regs + S3C64XX_SPI_PACKET_CNT); 371 regs + S3C64XX_SPI_PACKET_CNT);
336 info.cap = DMA_SLAVE; 372 prepare_dma(&sdd->rx_dma, xfer->len, xfer->rx_dma);
337 info.direction = DMA_FROM_DEVICE;
338 info.buf = xfer->rx_dma;
339 info.len = xfer->len;
340 info.fp = s3c64xx_spi_dma_rxcb;
341 info.fp_param = sdd;
342 sdd->ops->prepare(sdd->rx_ch, &info);
343 sdd->ops->trigger(sdd->rx_ch);
344 } 373 }
345 } 374 }
346 375
@@ -700,10 +729,10 @@ static void handle_msg(struct s3c64xx_spi_driver_data *sdd,
700 if (use_dma) { 729 if (use_dma) {
701 if (xfer->tx_buf != NULL 730 if (xfer->tx_buf != NULL
702 && (sdd->state & TXBUSY)) 731 && (sdd->state & TXBUSY))
703 sdd->ops->stop(sdd->tx_ch); 732 sdd->ops->stop(sdd->tx_dma.ch);
704 if (xfer->rx_buf != NULL 733 if (xfer->rx_buf != NULL
705 && (sdd->state & RXBUSY)) 734 && (sdd->state & RXBUSY))
706 sdd->ops->stop(sdd->rx_ch); 735 sdd->ops->stop(sdd->rx_dma.ch);
707 } 736 }
708 737
709 goto out; 738 goto out;
@@ -741,25 +770,6 @@ out:
741 msg->complete(msg->context); 770 msg->complete(msg->context);
742} 771}
743 772
744static int acquire_dma(struct s3c64xx_spi_driver_data *sdd)
745{
746
747 struct samsung_dma_info info;
748 sdd->ops = samsung_dma_get_ops();
749
750 info.cap = DMA_SLAVE;
751 info.client = &s3c64xx_spi_dma_client;
752 info.direction = DMA_FROM_DEVICE;
753 info.fifo = sdd->sfr_start + S3C64XX_SPI_RX_DATA;
754 info.width = sdd->cur_bpw / 8;
755 sdd->rx_ch = sdd->ops->request(sdd->rx_dmach, &info);
756 info.direction = DMA_TO_DEVICE;
757 info.fifo = sdd->sfr_start + S3C64XX_SPI_TX_DATA;
758 sdd->tx_ch = sdd->ops->request(sdd->tx_dmach, &info);
759
760 return 1;
761}
762
763static void s3c64xx_spi_work(struct work_struct *work) 773static void s3c64xx_spi_work(struct work_struct *work)
764{ 774{
765 struct s3c64xx_spi_driver_data *sdd = container_of(work, 775 struct s3c64xx_spi_driver_data *sdd = container_of(work,
@@ -796,8 +806,8 @@ static void s3c64xx_spi_work(struct work_struct *work)
796 spin_unlock_irqrestore(&sdd->lock, flags); 806 spin_unlock_irqrestore(&sdd->lock, flags);
797 807
798 /* Free DMA channels */ 808 /* Free DMA channels */
799 sdd->ops->release(sdd->rx_ch, &s3c64xx_spi_dma_client); 809 sdd->ops->release(sdd->rx_dma.ch, &s3c64xx_spi_dma_client);
800 sdd->ops->release(sdd->tx_ch, &s3c64xx_spi_dma_client); 810 sdd->ops->release(sdd->tx_dma.ch, &s3c64xx_spi_dma_client);
801} 811}
802 812
803static int s3c64xx_spi_transfer(struct spi_device *spi, 813static int s3c64xx_spi_transfer(struct spi_device *spi,
@@ -1014,8 +1024,10 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
1014 sdd->cntrlr_info = sci; 1024 sdd->cntrlr_info = sci;
1015 sdd->pdev = pdev; 1025 sdd->pdev = pdev;
1016 sdd->sfr_start = mem_res->start; 1026 sdd->sfr_start = mem_res->start;
1017 sdd->tx_dmach = dmatx_res->start; 1027 sdd->tx_dma.dmach = dmatx_res->start;
1018 sdd->rx_dmach = dmarx_res->start; 1028 sdd->tx_dma.direction = DMA_TO_DEVICE;
1029 sdd->rx_dma.dmach = dmarx_res->start;
1030 sdd->rx_dma.direction = DMA_FROM_DEVICE;
1019 1031
1020 sdd->cur_bpw = 8; 1032 sdd->cur_bpw = 8;
1021 1033
@@ -1103,7 +1115,7 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
1103 pdev->id, master->num_chipselect); 1115 pdev->id, master->num_chipselect);
1104 dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n", 1116 dev_dbg(&pdev->dev, "\tIOmem=[0x%x-0x%x]\tDMA=[Rx-%d, Tx-%d]\n",
1105 mem_res->end, mem_res->start, 1117 mem_res->end, mem_res->start,
1106 sdd->rx_dmach, sdd->tx_dmach); 1118 sdd->rx_dma.dmach, sdd->tx_dma.dmach);
1107 1119
1108 return 0; 1120 return 0;
1109 1121