Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
bf6xx-sport.c
Go to the documentation of this file.
1 /*
2  * bf6xx_sport.c Analog Devices BF6XX SPORT driver
3  *
4  * Copyright (c) 2012 Analog Devices Inc.
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License version 2 as
8  * published by the Free Software Foundation.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18  */
19 
20 #include <linux/device.h>
21 #include <linux/dma-mapping.h>
22 #include <linux/interrupt.h>
23 #include <linux/module.h>
24 #include <linux/platform_device.h>
25 #include <linux/slab.h>
26 
27 #include <asm/blackfin.h>
28 #include <asm/dma.h>
29 #include <asm/portmux.h>
30 
31 #include "bf6xx-sport.h"
32 
34  struct sport_params *params)
35 {
36  if (sport->tx_regs->spctl & SPORT_CTL_SPENPRI)
37  return -EBUSY;
38  sport->tx_regs->spctl = params->spctl | SPORT_CTL_SPTRAN;
39  sport->tx_regs->div = params->div;
40  SSYNC();
41  return 0;
42 }
44 
46  struct sport_params *params)
47 {
48  if (sport->rx_regs->spctl & SPORT_CTL_SPENPRI)
49  return -EBUSY;
50  sport->rx_regs->spctl = params->spctl & ~SPORT_CTL_SPTRAN;
51  sport->rx_regs->div = params->div;
52  SSYNC();
53  return 0;
54 }
56 
57 static int compute_wdsize(size_t wdsize)
58 {
59  switch (wdsize) {
60  case 1:
61  return WDSIZE_8 | PSIZE_8;
62  case 2:
63  return WDSIZE_16 | PSIZE_16;
64  default:
65  return WDSIZE_32 | PSIZE_32;
66  }
67 }
68 
69 void sport_tx_start(struct sport_device *sport)
70 {
71  set_dma_next_desc_addr(sport->tx_dma_chan, sport->tx_desc);
72  set_dma_config(sport->tx_dma_chan, DMAFLOW_LIST | DI_EN
73  | compute_wdsize(sport->wdsize) | NDSIZE_6);
74  enable_dma(sport->tx_dma_chan);
75  sport->tx_regs->spctl |= SPORT_CTL_SPENPRI;
76  SSYNC();
77 }
79 
80 void sport_rx_start(struct sport_device *sport)
81 {
82  set_dma_next_desc_addr(sport->rx_dma_chan, sport->rx_desc);
83  set_dma_config(sport->rx_dma_chan, DMAFLOW_LIST | DI_EN | WNR
84  | compute_wdsize(sport->wdsize) | NDSIZE_6);
85  enable_dma(sport->rx_dma_chan);
86  sport->rx_regs->spctl |= SPORT_CTL_SPENPRI;
87  SSYNC();
88 }
90 
91 void sport_tx_stop(struct sport_device *sport)
92 {
93  sport->tx_regs->spctl &= ~SPORT_CTL_SPENPRI;
94  SSYNC();
95  disable_dma(sport->tx_dma_chan);
96 }
98 
99 void sport_rx_stop(struct sport_device *sport)
100 {
101  sport->rx_regs->spctl &= ~SPORT_CTL_SPENPRI;
102  SSYNC();
103  disable_dma(sport->rx_dma_chan);
104 }
106 
108  void (*tx_callback)(void *), void *tx_data)
109 {
110  sport->tx_callback = tx_callback;
111  sport->tx_data = tx_data;
112 }
114 
116  void (*rx_callback)(void *), void *rx_data)
117 {
118  sport->rx_callback = rx_callback;
119  sport->rx_data = rx_data;
120 }
122 
123 static void setup_desc(struct dmasg *desc, void *buf, int fragcount,
124  size_t fragsize, unsigned int cfg,
125  unsigned int count, size_t wdsize)
126 {
127 
128  int i;
129 
130  for (i = 0; i < fragcount; ++i) {
131  desc[i].next_desc_addr = &(desc[i + 1]);
132  desc[i].start_addr = (unsigned long)buf + i*fragsize;
133  desc[i].cfg = cfg;
134  desc[i].x_count = count;
135  desc[i].x_modify = wdsize;
136  desc[i].y_count = 0;
137  desc[i].y_modify = 0;
138  }
139 
140  /* make circular */
141  desc[fragcount-1].next_desc_addr = desc;
142 }
143 
144 int sport_config_tx_dma(struct sport_device *sport, void *buf,
145  int fragcount, size_t fragsize)
146 {
147  unsigned int count;
148  unsigned int cfg;
150 
151  count = fragsize/sport->wdsize;
152 
153  if (sport->tx_desc)
155  sport->tx_desc, 0);
156 
158  fragcount * sizeof(struct dmasg), &addr, 0);
159  sport->tx_desc_size = fragcount * sizeof(struct dmasg);
160  if (!sport->tx_desc)
161  return -ENOMEM;
162 
163  sport->tx_buf = buf;
164  sport->tx_fragsize = fragsize;
165  sport->tx_frags = fragcount;
166  cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize) | NDSIZE_6;
167 
168  setup_desc(sport->tx_desc, buf, fragcount, fragsize,
169  cfg|DMAEN, count, sport->wdsize);
170 
171  return 0;
172 }
174 
175 int sport_config_rx_dma(struct sport_device *sport, void *buf,
176  int fragcount, size_t fragsize)
177 {
178  unsigned int count;
179  unsigned int cfg;
181 
182  count = fragsize/sport->wdsize;
183 
184  if (sport->rx_desc)
186  sport->rx_desc, 0);
187 
189  fragcount * sizeof(struct dmasg), &addr, 0);
190  sport->rx_desc_size = fragcount * sizeof(struct dmasg);
191  if (!sport->rx_desc)
192  return -ENOMEM;
193 
194  sport->rx_buf = buf;
195  sport->rx_fragsize = fragsize;
196  sport->rx_frags = fragcount;
197  cfg = DMAFLOW_LIST | DI_EN | compute_wdsize(sport->wdsize)
198  | WNR | NDSIZE_6;
199 
200  setup_desc(sport->rx_desc, buf, fragcount, fragsize,
201  cfg|DMAEN, count, sport->wdsize);
202 
203  return 0;
204 }
206 
207 unsigned long sport_curr_offset_tx(struct sport_device *sport)
208 {
209  unsigned long curr = get_dma_curr_addr(sport->tx_dma_chan);
210 
211  return (unsigned char *)curr - sport->tx_buf;
212 }
214 
215 unsigned long sport_curr_offset_rx(struct sport_device *sport)
216 {
217  unsigned long curr = get_dma_curr_addr(sport->rx_dma_chan);
218 
219  return (unsigned char *)curr - sport->rx_buf;
220 }
222 
223 static irqreturn_t sport_tx_irq(int irq, void *dev_id)
224 {
225  struct sport_device *sport = dev_id;
226  static unsigned long status;
227 
228  status = get_dma_curr_irqstat(sport->tx_dma_chan);
229  if (status & (DMA_DONE|DMA_ERR)) {
230  clear_dma_irqstat(sport->tx_dma_chan);
231  SSYNC();
232  }
233  if (sport->tx_callback)
234  sport->tx_callback(sport->tx_data);
235  return IRQ_HANDLED;
236 }
237 
238 static irqreturn_t sport_rx_irq(int irq, void *dev_id)
239 {
240  struct sport_device *sport = dev_id;
241  unsigned long status;
242 
243  status = get_dma_curr_irqstat(sport->rx_dma_chan);
244  if (status & (DMA_DONE|DMA_ERR)) {
245  clear_dma_irqstat(sport->rx_dma_chan);
246  SSYNC();
247  }
248  if (sport->rx_callback)
249  sport->rx_callback(sport->rx_data);
250  return IRQ_HANDLED;
251 }
252 
253 static irqreturn_t sport_err_irq(int irq, void *dev_id)
254 {
255  struct sport_device *sport = dev_id;
256  struct device *dev = &sport->pdev->dev;
257 
258  if (sport->tx_regs->spctl & SPORT_CTL_DERRPRI)
259  dev_err(dev, "sport error: TUVF\n");
260  if (sport->rx_regs->spctl & SPORT_CTL_DERRPRI)
261  dev_err(dev, "sport error: ROVF\n");
262 
263  return IRQ_HANDLED;
264 }
265 
266 static int sport_get_resource(struct sport_device *sport)
267 {
268  struct platform_device *pdev = sport->pdev;
269  struct device *dev = &pdev->dev;
271  struct resource *res;
272 
273  if (!pdata) {
274  dev_err(dev, "No platform data\n");
275  return -ENODEV;
276  }
277  sport->pin_req = pdata->pin_req;
278 
279  res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
280  if (!res) {
281  dev_err(dev, "No tx MEM resource\n");
282  return -ENODEV;
283  }
284  sport->tx_regs = (struct sport_register *)res->start;
285 
286  res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
287  if (!res) {
288  dev_err(dev, "No rx MEM resource\n");
289  return -ENODEV;
290  }
291  sport->rx_regs = (struct sport_register *)res->start;
292 
293  res = platform_get_resource(pdev, IORESOURCE_DMA, 0);
294  if (!res) {
295  dev_err(dev, "No tx DMA resource\n");
296  return -ENODEV;
297  }
298  sport->tx_dma_chan = res->start;
299 
300  res = platform_get_resource(pdev, IORESOURCE_DMA, 1);
301  if (!res) {
302  dev_err(dev, "No rx DMA resource\n");
303  return -ENODEV;
304  }
305  sport->rx_dma_chan = res->start;
306 
307  res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
308  if (!res) {
309  dev_err(dev, "No tx error irq resource\n");
310  return -ENODEV;
311  }
312  sport->tx_err_irq = res->start;
313 
314  res = platform_get_resource(pdev, IORESOURCE_IRQ, 1);
315  if (!res) {
316  dev_err(dev, "No rx error irq resource\n");
317  return -ENODEV;
318  }
319  sport->rx_err_irq = res->start;
320 
321  return 0;
322 }
323 
324 static int sport_request_resource(struct sport_device *sport)
325 {
326  struct device *dev = &sport->pdev->dev;
327  int ret;
328 
329  ret = peripheral_request_list(sport->pin_req, "soc-audio");
330  if (ret) {
331  dev_err(dev, "Unable to request sport pin\n");
332  return ret;
333  }
334 
335  ret = request_dma(sport->tx_dma_chan, "SPORT TX Data");
336  if (ret) {
337  dev_err(dev, "Unable to allocate DMA channel for sport tx\n");
338  goto err_tx_dma;
339  }
340  set_dma_callback(sport->tx_dma_chan, sport_tx_irq, sport);
341 
342  ret = request_dma(sport->rx_dma_chan, "SPORT RX Data");
343  if (ret) {
344  dev_err(dev, "Unable to allocate DMA channel for sport rx\n");
345  goto err_rx_dma;
346  }
347  set_dma_callback(sport->rx_dma_chan, sport_rx_irq, sport);
348 
349  ret = request_irq(sport->tx_err_irq, sport_err_irq,
350  0, "SPORT TX ERROR", sport);
351  if (ret) {
352  dev_err(dev, "Unable to allocate tx error IRQ for sport\n");
353  goto err_tx_irq;
354  }
355 
356  ret = request_irq(sport->rx_err_irq, sport_err_irq,
357  0, "SPORT RX ERROR", sport);
358  if (ret) {
359  dev_err(dev, "Unable to allocate rx error IRQ for sport\n");
360  goto err_rx_irq;
361  }
362 
363  return 0;
364 err_rx_irq:
365  free_irq(sport->tx_err_irq, sport);
366 err_tx_irq:
367  free_dma(sport->rx_dma_chan);
368 err_rx_dma:
369  free_dma(sport->tx_dma_chan);
370 err_tx_dma:
372  return ret;
373 }
374 
375 static void sport_free_resource(struct sport_device *sport)
376 {
377  free_irq(sport->rx_err_irq, sport);
378  free_irq(sport->tx_err_irq, sport);
379  free_dma(sport->rx_dma_chan);
380  free_dma(sport->tx_dma_chan);
382 }
383 
385 {
386  struct device *dev = &pdev->dev;
387  struct sport_device *sport;
388  int ret;
389 
390  sport = kzalloc(sizeof(*sport), GFP_KERNEL);
391  if (!sport) {
392  dev_err(dev, "Unable to allocate memory for sport device\n");
393  return NULL;
394  }
395  sport->pdev = pdev;
396 
397  ret = sport_get_resource(sport);
398  if (ret) {
399  kfree(sport);
400  return NULL;
401  }
402 
403  ret = sport_request_resource(sport);
404  if (ret) {
405  kfree(sport);
406  return NULL;
407  }
408 
409  dev_dbg(dev, "SPORT create success\n");
410  return sport;
411 }
413 
414 void sport_delete(struct sport_device *sport)
415 {
416  if (sport->tx_desc)
418  sport->tx_desc, 0);
419  if (sport->rx_desc)
421  sport->rx_desc, 0);
422  sport_free_resource(sport);
423  kfree(sport);
424 }
426 
427 MODULE_DESCRIPTION("Analog Devices BF6XX SPORT driver");
428 MODULE_AUTHOR("Scott Jiang <[email protected]>");
429 MODULE_LICENSE("GPL v2");