Merge tag 'xfs-for-linus-v3.12-rc1-2' of git://oss.sgi.com/xfs/xfs
[cascardo/linux.git] / drivers / media / platform / blackfin / ppi.c
1 /*
2  * ppi.c Analog Devices Parallel Peripheral Interface driver
3  *
4  * Copyright (c) 2011 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/module.h>
21 #include <linux/slab.h>
22
23 #include <asm/bfin_ppi.h>
24 #include <asm/blackfin.h>
25 #include <asm/cacheflush.h>
26 #include <asm/dma.h>
27 #include <asm/portmux.h>
28
29 #include <media/blackfin/ppi.h>
30
31 static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler);
32 static void ppi_detach_irq(struct ppi_if *ppi);
33 static int ppi_start(struct ppi_if *ppi);
34 static int ppi_stop(struct ppi_if *ppi);
35 static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params);
36 static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr);
37
38 static const struct ppi_ops ppi_ops = {
39         .attach_irq = ppi_attach_irq,
40         .detach_irq = ppi_detach_irq,
41         .start = ppi_start,
42         .stop = ppi_stop,
43         .set_params = ppi_set_params,
44         .update_addr = ppi_update_addr,
45 };
46
47 static irqreturn_t ppi_irq_err(int irq, void *dev_id)
48 {
49         struct ppi_if *ppi = dev_id;
50         const struct ppi_info *info = ppi->info;
51
52         switch (info->type) {
53         case PPI_TYPE_PPI:
54         {
55                 struct bfin_ppi_regs *reg = info->base;
56                 unsigned short status;
57
58                 /* register on bf561 is cleared when read 
59                  * others are W1C
60                  */
61                 status = bfin_read16(&reg->status);
62                 if (status & 0x3000)
63                         ppi->err = true;
64                 bfin_write16(&reg->status, 0xff00);
65                 break;
66         }
67         case PPI_TYPE_EPPI:
68         {
69                 struct bfin_eppi_regs *reg = info->base;
70                 unsigned short status;
71
72                 status = bfin_read16(&reg->status);
73                 if (status & 0x2)
74                         ppi->err = true;
75                 bfin_write16(&reg->status, 0xffff);
76                 break;
77         }
78         case PPI_TYPE_EPPI3:
79         {
80                 struct bfin_eppi3_regs *reg = info->base;
81                 unsigned long stat;
82
83                 stat = bfin_read32(&reg->stat);
84                 if (stat & 0x2)
85                         ppi->err = true;
86                 bfin_write32(&reg->stat, 0xc0ff);
87                 break;
88         }
89         default:
90                 break;
91         }
92
93         return IRQ_HANDLED;
94 }
95
96 static int ppi_attach_irq(struct ppi_if *ppi, irq_handler_t handler)
97 {
98         const struct ppi_info *info = ppi->info;
99         int ret;
100
101         ret = request_dma(info->dma_ch, "PPI_DMA");
102
103         if (ret) {
104                 pr_err("Unable to allocate DMA channel for PPI\n");
105                 return ret;
106         }
107         set_dma_callback(info->dma_ch, handler, ppi);
108
109         if (ppi->err_int) {
110                 ret = request_irq(info->irq_err, ppi_irq_err, 0, "PPI ERROR", ppi);
111                 if (ret) {
112                         pr_err("Unable to allocate IRQ for PPI\n");
113                         free_dma(info->dma_ch);
114                 }
115         }
116         return ret;
117 }
118
119 static void ppi_detach_irq(struct ppi_if *ppi)
120 {
121         const struct ppi_info *info = ppi->info;
122
123         if (ppi->err_int)
124                 free_irq(info->irq_err, ppi);
125         free_dma(info->dma_ch);
126 }
127
128 static int ppi_start(struct ppi_if *ppi)
129 {
130         const struct ppi_info *info = ppi->info;
131
132         /* enable DMA */
133         enable_dma(info->dma_ch);
134
135         /* enable PPI */
136         ppi->ppi_control |= PORT_EN;
137         switch (info->type) {
138         case PPI_TYPE_PPI:
139         {
140                 struct bfin_ppi_regs *reg = info->base;
141                 bfin_write16(&reg->control, ppi->ppi_control);
142                 break;
143         }
144         case PPI_TYPE_EPPI:
145         {
146                 struct bfin_eppi_regs *reg = info->base;
147                 bfin_write32(&reg->control, ppi->ppi_control);
148                 break;
149         }
150         case PPI_TYPE_EPPI3:
151         {
152                 struct bfin_eppi3_regs *reg = info->base;
153                 bfin_write32(&reg->ctl, ppi->ppi_control);
154                 break;
155         }
156         default:
157                 return -EINVAL;
158         }
159
160         SSYNC();
161         return 0;
162 }
163
164 static int ppi_stop(struct ppi_if *ppi)
165 {
166         const struct ppi_info *info = ppi->info;
167
168         /* disable PPI */
169         ppi->ppi_control &= ~PORT_EN;
170         switch (info->type) {
171         case PPI_TYPE_PPI:
172         {
173                 struct bfin_ppi_regs *reg = info->base;
174                 bfin_write16(&reg->control, ppi->ppi_control);
175                 break;
176         }
177         case PPI_TYPE_EPPI:
178         {
179                 struct bfin_eppi_regs *reg = info->base;
180                 bfin_write32(&reg->control, ppi->ppi_control);
181                 break;
182         }
183         case PPI_TYPE_EPPI3:
184         {
185                 struct bfin_eppi3_regs *reg = info->base;
186                 bfin_write32(&reg->ctl, ppi->ppi_control);
187                 break;
188         }
189         default:
190                 return -EINVAL;
191         }
192
193         /* disable DMA */
194         clear_dma_irqstat(info->dma_ch);
195         disable_dma(info->dma_ch);
196
197         SSYNC();
198         return 0;
199 }
200
201 static int ppi_set_params(struct ppi_if *ppi, struct ppi_params *params)
202 {
203         const struct ppi_info *info = ppi->info;
204         int dma32 = 0;
205         int dma_config, bytes_per_line;
206         int hcount, hdelay, samples_per_line;
207
208         bytes_per_line = params->width * params->bpp / 8;
209         /* convert parameters unit from pixels to samples */
210         hcount = params->width * params->bpp / params->dlen;
211         hdelay = params->hdelay * params->bpp / params->dlen;
212         samples_per_line = params->line * params->bpp / params->dlen;
213         if (params->int_mask == 0xFFFFFFFF)
214                 ppi->err_int = false;
215         else
216                 ppi->err_int = true;
217
218         dma_config = (DMA_FLOW_STOP | RESTART | DMA2D | DI_EN_Y);
219         ppi->ppi_control = params->ppi_control & ~PORT_EN;
220         if (!(ppi->ppi_control & PORT_DIR))
221                 dma_config |= WNR;
222         switch (info->type) {
223         case PPI_TYPE_PPI:
224         {
225                 struct bfin_ppi_regs *reg = info->base;
226
227                 if (params->ppi_control & DMA32)
228                         dma32 = 1;
229
230                 bfin_write16(&reg->control, ppi->ppi_control);
231                 bfin_write16(&reg->count, samples_per_line - 1);
232                 bfin_write16(&reg->frame, params->frame);
233                 break;
234         }
235         case PPI_TYPE_EPPI:
236         {
237                 struct bfin_eppi_regs *reg = info->base;
238
239                 if ((params->ppi_control & PACK_EN)
240                         || (params->ppi_control & 0x38000) > DLEN_16)
241                         dma32 = 1;
242
243                 bfin_write32(&reg->control, ppi->ppi_control);
244                 bfin_write16(&reg->line, samples_per_line);
245                 bfin_write16(&reg->frame, params->frame);
246                 bfin_write16(&reg->hdelay, hdelay);
247                 bfin_write16(&reg->vdelay, params->vdelay);
248                 bfin_write16(&reg->hcount, hcount);
249                 bfin_write16(&reg->vcount, params->height);
250                 break;
251         }
252         case PPI_TYPE_EPPI3:
253         {
254                 struct bfin_eppi3_regs *reg = info->base;
255
256                 if ((params->ppi_control & PACK_EN)
257                         || (params->ppi_control & 0x70000) > DLEN_16)
258                         dma32 = 1;
259
260                 bfin_write32(&reg->ctl, ppi->ppi_control);
261                 bfin_write32(&reg->line, samples_per_line);
262                 bfin_write32(&reg->frame, params->frame);
263                 bfin_write32(&reg->hdly, hdelay);
264                 bfin_write32(&reg->vdly, params->vdelay);
265                 bfin_write32(&reg->hcnt, hcount);
266                 bfin_write32(&reg->vcnt, params->height);
267                 if (params->int_mask)
268                         bfin_write32(&reg->imsk, params->int_mask & 0xFF);
269                 if (ppi->ppi_control & PORT_DIR) {
270                         u32 hsync_width, vsync_width, vsync_period;
271
272                         hsync_width = params->hsync
273                                         * params->bpp / params->dlen;
274                         vsync_width = params->vsync * samples_per_line;
275                         vsync_period = samples_per_line * params->frame;
276                         bfin_write32(&reg->fs1_wlhb, hsync_width);
277                         bfin_write32(&reg->fs1_paspl, samples_per_line);
278                         bfin_write32(&reg->fs2_wlvb, vsync_width);
279                         bfin_write32(&reg->fs2_palpf, vsync_period);
280                 }
281                 break;
282         }
283         default:
284                 return -EINVAL;
285         }
286
287         if (dma32) {
288                 dma_config |= WDSIZE_32 | PSIZE_32;
289                 set_dma_x_count(info->dma_ch, bytes_per_line >> 2);
290                 set_dma_x_modify(info->dma_ch, 4);
291                 set_dma_y_modify(info->dma_ch, 4);
292         } else {
293                 dma_config |= WDSIZE_16 | PSIZE_16;
294                 set_dma_x_count(info->dma_ch, bytes_per_line >> 1);
295                 set_dma_x_modify(info->dma_ch, 2);
296                 set_dma_y_modify(info->dma_ch, 2);
297         }
298         set_dma_y_count(info->dma_ch, params->height);
299         set_dma_config(info->dma_ch, dma_config);
300
301         SSYNC();
302         return 0;
303 }
304
305 static void ppi_update_addr(struct ppi_if *ppi, unsigned long addr)
306 {
307         set_dma_start_addr(ppi->info->dma_ch, addr);
308 }
309
310 struct ppi_if *ppi_create_instance(const struct ppi_info *info)
311 {
312         struct ppi_if *ppi;
313
314         if (!info || !info->pin_req)
315                 return NULL;
316
317         if (peripheral_request_list(info->pin_req, KBUILD_MODNAME)) {
318                 pr_err("request peripheral failed\n");
319                 return NULL;
320         }
321
322         ppi = kzalloc(sizeof(*ppi), GFP_KERNEL);
323         if (!ppi) {
324                 peripheral_free_list(info->pin_req);
325                 pr_err("unable to allocate memory for ppi handle\n");
326                 return NULL;
327         }
328         ppi->ops = &ppi_ops;
329         ppi->info = info;
330
331         pr_info("ppi probe success\n");
332         return ppi;
333 }
334 EXPORT_SYMBOL(ppi_create_instance);
335
336 void ppi_delete_instance(struct ppi_if *ppi)
337 {
338         peripheral_free_list(ppi->info->pin_req);
339         kfree(ppi);
340 }
341 EXPORT_SYMBOL(ppi_delete_instance);
342
343 MODULE_DESCRIPTION("Analog Devices PPI driver");
344 MODULE_AUTHOR("Scott Jiang <Scott.Jiang.Linux@gmail.com>");
345 MODULE_LICENSE("GPL v2");