Version:  2.0.40 2.2.26 2.4.37 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 3.19 4.0 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8

Linux/drivers/media/platform/soc_camera/atmel-isi.c

  1 /*
  2  * Copyright (c) 2011 Atmel Corporation
  3  * Josh Wu, <josh.wu@atmel.com>
  4  *
  5  * Based on previous work by Lars Haring, <lars.haring@atmel.com>
  6  * and Sedji Gaouaou
  7  * Based on the bttv driver for Bt848 with respective copyright holders
  8  *
  9  * This program is free software; you can redistribute it and/or modify
 10  * it under the terms of the GNU General Public License version 2 as
 11  * published by the Free Software Foundation.
 12  */
 13 
 14 #include <linux/clk.h>
 15 #include <linux/completion.h>
 16 #include <linux/delay.h>
 17 #include <linux/fs.h>
 18 #include <linux/init.h>
 19 #include <linux/interrupt.h>
 20 #include <linux/kernel.h>
 21 #include <linux/module.h>
 22 #include <linux/platform_device.h>
 23 #include <linux/pm_runtime.h>
 24 #include <linux/slab.h>
 25 
 26 #include <media/soc_camera.h>
 27 #include <media/drv-intf/soc_mediabus.h>
 28 #include <media/v4l2-of.h>
 29 #include <media/videobuf2-dma-contig.h>
 30 
 31 #include "atmel-isi.h"
 32 
 33 #define MAX_BUFFER_NUM                  32
 34 #define MAX_SUPPORT_WIDTH               2048
 35 #define MAX_SUPPORT_HEIGHT              2048
 36 #define VID_LIMIT_BYTES                 (16 * 1024 * 1024)
 37 #define MIN_FRAME_RATE                  15
 38 #define FRAME_INTERVAL_MILLI_SEC        (1000 / MIN_FRAME_RATE)
 39 
 40 /* Frame buffer descriptor */
 41 struct fbd {
 42         /* Physical address of the frame buffer */
 43         u32 fb_address;
 44         /* DMA Control Register(only in HISI2) */
 45         u32 dma_ctrl;
 46         /* Physical address of the next fbd */
 47         u32 next_fbd_address;
 48 };
 49 
 50 static void set_dma_ctrl(struct fbd *fb_desc, u32 ctrl)
 51 {
 52         fb_desc->dma_ctrl = ctrl;
 53 }
 54 
 55 struct isi_dma_desc {
 56         struct list_head list;
 57         struct fbd *p_fbd;
 58         dma_addr_t fbd_phys;
 59 };
 60 
 61 /* Frame buffer data */
 62 struct frame_buffer {
 63         struct vb2_v4l2_buffer vb;
 64         struct isi_dma_desc *p_dma_desc;
 65         struct list_head list;
 66 };
 67 
 68 struct atmel_isi {
 69         /* Protects the access of variables shared with the ISR */
 70         spinlock_t                      lock;
 71         void __iomem                    *regs;
 72 
 73         int                             sequence;
 74 
 75         /* Allocate descriptors for dma buffer use */
 76         struct fbd                      *p_fb_descriptors;
 77         dma_addr_t                      fb_descriptors_phys;
 78         struct                          list_head dma_desc_head;
 79         struct isi_dma_desc             dma_desc[MAX_BUFFER_NUM];
 80         bool                            enable_preview_path;
 81 
 82         struct completion               complete;
 83         /* ISI peripherial clock */
 84         struct clk                      *pclk;
 85         unsigned int                    irq;
 86 
 87         struct isi_platform_data        pdata;
 88         u16                             width_flags;    /* max 12 bits */
 89 
 90         struct list_head                video_buffer_list;
 91         struct frame_buffer             *active;
 92 
 93         struct soc_camera_host          soc_host;
 94 };
 95 
 96 static void isi_writel(struct atmel_isi *isi, u32 reg, u32 val)
 97 {
 98         writel(val, isi->regs + reg);
 99 }
100 static u32 isi_readl(struct atmel_isi *isi, u32 reg)
101 {
102         return readl(isi->regs + reg);
103 }
104 
105 static u32 setup_cfg2_yuv_swap(struct atmel_isi *isi,
106                 const struct soc_camera_format_xlate *xlate)
107 {
108         if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_YUYV) {
109                 /* all convert to YUYV */
110                 switch (xlate->code) {
111                 case MEDIA_BUS_FMT_VYUY8_2X8:
112                         return ISI_CFG2_YCC_SWAP_MODE_3;
113                 case MEDIA_BUS_FMT_UYVY8_2X8:
114                         return ISI_CFG2_YCC_SWAP_MODE_2;
115                 case MEDIA_BUS_FMT_YVYU8_2X8:
116                         return ISI_CFG2_YCC_SWAP_MODE_1;
117                 }
118         } else if (xlate->host_fmt->fourcc == V4L2_PIX_FMT_RGB565) {
119                 /*
120                  * Preview path is enabled, it will convert UYVY to RGB format.
121                  * But if sensor output format is not UYVY, we need to set
122                  * YCC_SWAP_MODE to convert it as UYVY.
123                  */
124                 switch (xlate->code) {
125                 case MEDIA_BUS_FMT_VYUY8_2X8:
126                         return ISI_CFG2_YCC_SWAP_MODE_1;
127                 case MEDIA_BUS_FMT_YUYV8_2X8:
128                         return ISI_CFG2_YCC_SWAP_MODE_2;
129                 case MEDIA_BUS_FMT_YVYU8_2X8:
130                         return ISI_CFG2_YCC_SWAP_MODE_3;
131                 }
132         }
133 
134         /*
135          * By default, no swap for the codec path of Atmel ISI. So codec
136          * output is same as sensor's output.
137          * For instance, if sensor's output is YUYV, then codec outputs YUYV.
138          * And if sensor's output is UYVY, then codec outputs UYVY.
139          */
140         return ISI_CFG2_YCC_SWAP_DEFAULT;
141 }
142 
143 static void configure_geometry(struct atmel_isi *isi, u32 width,
144                 u32 height, const struct soc_camera_format_xlate *xlate)
145 {
146         u32 cfg2, psize;
147         u32 fourcc = xlate->host_fmt->fourcc;
148 
149         isi->enable_preview_path = fourcc == V4L2_PIX_FMT_RGB565 ||
150                                    fourcc == V4L2_PIX_FMT_RGB32;
151 
152         /* According to sensor's output format to set cfg2 */
153         switch (xlate->code) {
154         default:
155         /* Grey */
156         case MEDIA_BUS_FMT_Y8_1X8:
157                 cfg2 = ISI_CFG2_GRAYSCALE | ISI_CFG2_COL_SPACE_YCbCr;
158                 break;
159         /* YUV */
160         case MEDIA_BUS_FMT_VYUY8_2X8:
161         case MEDIA_BUS_FMT_UYVY8_2X8:
162         case MEDIA_BUS_FMT_YVYU8_2X8:
163         case MEDIA_BUS_FMT_YUYV8_2X8:
164                 cfg2 = ISI_CFG2_COL_SPACE_YCbCr |
165                                 setup_cfg2_yuv_swap(isi, xlate);
166                 break;
167         /* RGB, TODO */
168         }
169 
170         isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
171         /* Set width */
172         cfg2 |= ((width - 1) << ISI_CFG2_IM_HSIZE_OFFSET) &
173                         ISI_CFG2_IM_HSIZE_MASK;
174         /* Set height */
175         cfg2 |= ((height - 1) << ISI_CFG2_IM_VSIZE_OFFSET)
176                         & ISI_CFG2_IM_VSIZE_MASK;
177         isi_writel(isi, ISI_CFG2, cfg2);
178 
179         /* No down sampling, preview size equal to sensor output size */
180         psize = ((width - 1) << ISI_PSIZE_PREV_HSIZE_OFFSET) &
181                 ISI_PSIZE_PREV_HSIZE_MASK;
182         psize |= ((height - 1) << ISI_PSIZE_PREV_VSIZE_OFFSET) &
183                 ISI_PSIZE_PREV_VSIZE_MASK;
184         isi_writel(isi, ISI_PSIZE, psize);
185         isi_writel(isi, ISI_PDECF, ISI_PDECF_NO_SAMPLING);
186 
187         return;
188 }
189 
190 static bool is_supported(struct soc_camera_device *icd,
191                 const u32 pixformat)
192 {
193         switch (pixformat) {
194         /* YUV, including grey */
195         case V4L2_PIX_FMT_GREY:
196         case V4L2_PIX_FMT_YUYV:
197         case V4L2_PIX_FMT_UYVY:
198         case V4L2_PIX_FMT_YVYU:
199         case V4L2_PIX_FMT_VYUY:
200         /* RGB */
201         case V4L2_PIX_FMT_RGB565:
202                 return true;
203         default:
204                 return false;
205         }
206 }
207 
208 static irqreturn_t atmel_isi_handle_streaming(struct atmel_isi *isi)
209 {
210         if (isi->active) {
211                 struct vb2_v4l2_buffer *vbuf = &isi->active->vb;
212                 struct frame_buffer *buf = isi->active;
213 
214                 list_del_init(&buf->list);
215                 vbuf->vb2_buf.timestamp = ktime_get_ns();
216                 vbuf->sequence = isi->sequence++;
217                 vb2_buffer_done(&vbuf->vb2_buf, VB2_BUF_STATE_DONE);
218         }
219 
220         if (list_empty(&isi->video_buffer_list)) {
221                 isi->active = NULL;
222         } else {
223                 /* start next dma frame. */
224                 isi->active = list_entry(isi->video_buffer_list.next,
225                                         struct frame_buffer, list);
226                 if (!isi->enable_preview_path) {
227                         isi_writel(isi, ISI_DMA_C_DSCR,
228                                 (u32)isi->active->p_dma_desc->fbd_phys);
229                         isi_writel(isi, ISI_DMA_C_CTRL,
230                                 ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
231                         isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
232                 } else {
233                         isi_writel(isi, ISI_DMA_P_DSCR,
234                                 (u32)isi->active->p_dma_desc->fbd_phys);
235                         isi_writel(isi, ISI_DMA_P_CTRL,
236                                 ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
237                         isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH);
238                 }
239         }
240         return IRQ_HANDLED;
241 }
242 
243 /* ISI interrupt service routine */
244 static irqreturn_t isi_interrupt(int irq, void *dev_id)
245 {
246         struct atmel_isi *isi = dev_id;
247         u32 status, mask, pending;
248         irqreturn_t ret = IRQ_NONE;
249 
250         spin_lock(&isi->lock);
251 
252         status = isi_readl(isi, ISI_STATUS);
253         mask = isi_readl(isi, ISI_INTMASK);
254         pending = status & mask;
255 
256         if (pending & ISI_CTRL_SRST) {
257                 complete(&isi->complete);
258                 isi_writel(isi, ISI_INTDIS, ISI_CTRL_SRST);
259                 ret = IRQ_HANDLED;
260         } else if (pending & ISI_CTRL_DIS) {
261                 complete(&isi->complete);
262                 isi_writel(isi, ISI_INTDIS, ISI_CTRL_DIS);
263                 ret = IRQ_HANDLED;
264         } else {
265                 if (likely(pending & ISI_SR_CXFR_DONE) ||
266                                 likely(pending & ISI_SR_PXFR_DONE))
267                         ret = atmel_isi_handle_streaming(isi);
268         }
269 
270         spin_unlock(&isi->lock);
271         return ret;
272 }
273 
274 #define WAIT_ISI_RESET          1
275 #define WAIT_ISI_DISABLE        0
276 static int atmel_isi_wait_status(struct atmel_isi *isi, int wait_reset)
277 {
278         unsigned long timeout;
279         /*
280          * The reset or disable will only succeed if we have a
281          * pixel clock from the camera.
282          */
283         init_completion(&isi->complete);
284 
285         if (wait_reset) {
286                 isi_writel(isi, ISI_INTEN, ISI_CTRL_SRST);
287                 isi_writel(isi, ISI_CTRL, ISI_CTRL_SRST);
288         } else {
289                 isi_writel(isi, ISI_INTEN, ISI_CTRL_DIS);
290                 isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
291         }
292 
293         timeout = wait_for_completion_timeout(&isi->complete,
294                         msecs_to_jiffies(500));
295         if (timeout == 0)
296                 return -ETIMEDOUT;
297 
298         return 0;
299 }
300 
301 /* ------------------------------------------------------------------
302         Videobuf operations
303    ------------------------------------------------------------------*/
304 static int queue_setup(struct vb2_queue *vq,
305                                 unsigned int *nbuffers, unsigned int *nplanes,
306                                 unsigned int sizes[], struct device *alloc_devs[])
307 {
308         struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
309         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
310         struct atmel_isi *isi = ici->priv;
311         unsigned long size;
312 
313         size = icd->sizeimage;
314 
315         if (!*nbuffers || *nbuffers > MAX_BUFFER_NUM)
316                 *nbuffers = MAX_BUFFER_NUM;
317 
318         if (size * *nbuffers > VID_LIMIT_BYTES)
319                 *nbuffers = VID_LIMIT_BYTES / size;
320 
321         *nplanes = 1;
322         sizes[0] = size;
323 
324         isi->sequence = 0;
325         isi->active = NULL;
326 
327         dev_dbg(icd->parent, "%s, count=%d, size=%ld\n", __func__,
328                 *nbuffers, size);
329 
330         return 0;
331 }
332 
333 static int buffer_init(struct vb2_buffer *vb)
334 {
335         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
336         struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb);
337 
338         buf->p_dma_desc = NULL;
339         INIT_LIST_HEAD(&buf->list);
340 
341         return 0;
342 }
343 
344 static int buffer_prepare(struct vb2_buffer *vb)
345 {
346         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
347         struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
348         struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb);
349         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
350         struct atmel_isi *isi = ici->priv;
351         unsigned long size;
352         struct isi_dma_desc *desc;
353 
354         size = icd->sizeimage;
355 
356         if (vb2_plane_size(vb, 0) < size) {
357                 dev_err(icd->parent, "%s data will not fit into plane (%lu < %lu)\n",
358                                 __func__, vb2_plane_size(vb, 0), size);
359                 return -EINVAL;
360         }
361 
362         vb2_set_plane_payload(vb, 0, size);
363 
364         if (!buf->p_dma_desc) {
365                 if (list_empty(&isi->dma_desc_head)) {
366                         dev_err(icd->parent, "Not enough dma descriptors.\n");
367                         return -EINVAL;
368                 } else {
369                         /* Get an available descriptor */
370                         desc = list_entry(isi->dma_desc_head.next,
371                                                 struct isi_dma_desc, list);
372                         /* Delete the descriptor since now it is used */
373                         list_del_init(&desc->list);
374 
375                         /* Initialize the dma descriptor */
376                         desc->p_fbd->fb_address =
377                                         vb2_dma_contig_plane_dma_addr(vb, 0);
378                         desc->p_fbd->next_fbd_address = 0;
379                         set_dma_ctrl(desc->p_fbd, ISI_DMA_CTRL_WB);
380 
381                         buf->p_dma_desc = desc;
382                 }
383         }
384         return 0;
385 }
386 
387 static void buffer_cleanup(struct vb2_buffer *vb)
388 {
389         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
390         struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
391         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
392         struct atmel_isi *isi = ici->priv;
393         struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb);
394 
395         /* This descriptor is available now and we add to head list */
396         if (buf->p_dma_desc)
397                 list_add(&buf->p_dma_desc->list, &isi->dma_desc_head);
398 }
399 
400 static void start_dma(struct atmel_isi *isi, struct frame_buffer *buffer)
401 {
402         u32 ctrl, cfg1;
403 
404         cfg1 = isi_readl(isi, ISI_CFG1);
405         /* Enable irq: cxfr for the codec path, pxfr for the preview path */
406         isi_writel(isi, ISI_INTEN,
407                         ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
408 
409         /* Check if already in a frame */
410         if (!isi->enable_preview_path) {
411                 if (isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) {
412                         dev_err(isi->soc_host.icd->parent, "Already in frame handling.\n");
413                         return;
414                 }
415 
416                 isi_writel(isi, ISI_DMA_C_DSCR,
417                                 (u32)buffer->p_dma_desc->fbd_phys);
418                 isi_writel(isi, ISI_DMA_C_CTRL,
419                                 ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
420                 isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_C_CH);
421         } else {
422                 isi_writel(isi, ISI_DMA_P_DSCR,
423                                 (u32)buffer->p_dma_desc->fbd_phys);
424                 isi_writel(isi, ISI_DMA_P_CTRL,
425                                 ISI_DMA_CTRL_FETCH | ISI_DMA_CTRL_DONE);
426                 isi_writel(isi, ISI_DMA_CHER, ISI_DMA_CHSR_P_CH);
427         }
428 
429         cfg1 &= ~ISI_CFG1_FRATE_DIV_MASK;
430         /* Enable linked list */
431         cfg1 |= isi->pdata.frate | ISI_CFG1_DISCR;
432 
433         /* Enable ISI */
434         ctrl = ISI_CTRL_EN;
435 
436         if (!isi->enable_preview_path)
437                 ctrl |= ISI_CTRL_CDC;
438 
439         isi_writel(isi, ISI_CTRL, ctrl);
440         isi_writel(isi, ISI_CFG1, cfg1);
441 }
442 
443 static void buffer_queue(struct vb2_buffer *vb)
444 {
445         struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
446         struct soc_camera_device *icd = soc_camera_from_vb2q(vb->vb2_queue);
447         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
448         struct atmel_isi *isi = ici->priv;
449         struct frame_buffer *buf = container_of(vbuf, struct frame_buffer, vb);
450         unsigned long flags = 0;
451 
452         spin_lock_irqsave(&isi->lock, flags);
453         list_add_tail(&buf->list, &isi->video_buffer_list);
454 
455         if (isi->active == NULL) {
456                 isi->active = buf;
457                 if (vb2_is_streaming(vb->vb2_queue))
458                         start_dma(isi, buf);
459         }
460         spin_unlock_irqrestore(&isi->lock, flags);
461 }
462 
463 static int start_streaming(struct vb2_queue *vq, unsigned int count)
464 {
465         struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
466         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
467         struct atmel_isi *isi = ici->priv;
468         int ret;
469 
470         pm_runtime_get_sync(ici->v4l2_dev.dev);
471 
472         /* Reset ISI */
473         ret = atmel_isi_wait_status(isi, WAIT_ISI_RESET);
474         if (ret < 0) {
475                 dev_err(icd->parent, "Reset ISI timed out\n");
476                 pm_runtime_put(ici->v4l2_dev.dev);
477                 return ret;
478         }
479         /* Disable all interrupts */
480         isi_writel(isi, ISI_INTDIS, (u32)~0UL);
481 
482         configure_geometry(isi, icd->user_width, icd->user_height,
483                                 icd->current_fmt);
484 
485         spin_lock_irq(&isi->lock);
486         /* Clear any pending interrupt */
487         isi_readl(isi, ISI_STATUS);
488 
489         if (count)
490                 start_dma(isi, isi->active);
491         spin_unlock_irq(&isi->lock);
492 
493         return 0;
494 }
495 
496 /* abort streaming and wait for last buffer */
497 static void stop_streaming(struct vb2_queue *vq)
498 {
499         struct soc_camera_device *icd = soc_camera_from_vb2q(vq);
500         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
501         struct atmel_isi *isi = ici->priv;
502         struct frame_buffer *buf, *node;
503         int ret = 0;
504         unsigned long timeout;
505 
506         spin_lock_irq(&isi->lock);
507         isi->active = NULL;
508         /* Release all active buffers */
509         list_for_each_entry_safe(buf, node, &isi->video_buffer_list, list) {
510                 list_del_init(&buf->list);
511                 vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
512         }
513         spin_unlock_irq(&isi->lock);
514 
515         if (!isi->enable_preview_path) {
516                 timeout = jiffies + FRAME_INTERVAL_MILLI_SEC * HZ;
517                 /* Wait until the end of the current frame. */
518                 while ((isi_readl(isi, ISI_STATUS) & ISI_CTRL_CDC) &&
519                                 time_before(jiffies, timeout))
520                         msleep(1);
521 
522                 if (time_after(jiffies, timeout))
523                         dev_err(icd->parent,
524                                 "Timeout waiting for finishing codec request\n");
525         }
526 
527         /* Disable interrupts */
528         isi_writel(isi, ISI_INTDIS,
529                         ISI_SR_CXFR_DONE | ISI_SR_PXFR_DONE);
530 
531         /* Disable ISI and wait for it is done */
532         ret = atmel_isi_wait_status(isi, WAIT_ISI_DISABLE);
533         if (ret < 0)
534                 dev_err(icd->parent, "Disable ISI timed out\n");
535 
536         pm_runtime_put(ici->v4l2_dev.dev);
537 }
538 
539 static struct vb2_ops isi_video_qops = {
540         .queue_setup            = queue_setup,
541         .buf_init               = buffer_init,
542         .buf_prepare            = buffer_prepare,
543         .buf_cleanup            = buffer_cleanup,
544         .buf_queue              = buffer_queue,
545         .start_streaming        = start_streaming,
546         .stop_streaming         = stop_streaming,
547         .wait_prepare           = vb2_ops_wait_prepare,
548         .wait_finish            = vb2_ops_wait_finish,
549 };
550 
551 /* ------------------------------------------------------------------
552         SOC camera operations for the device
553    ------------------------------------------------------------------*/
554 static int isi_camera_init_videobuf(struct vb2_queue *q,
555                                      struct soc_camera_device *icd)
556 {
557         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
558 
559         q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
560         q->io_modes = VB2_MMAP;
561         q->drv_priv = icd;
562         q->buf_struct_size = sizeof(struct frame_buffer);
563         q->ops = &isi_video_qops;
564         q->mem_ops = &vb2_dma_contig_memops;
565         q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
566         q->lock = &ici->host_lock;
567         q->dev = ici->v4l2_dev.dev;
568 
569         return vb2_queue_init(q);
570 }
571 
572 static int isi_camera_set_fmt(struct soc_camera_device *icd,
573                               struct v4l2_format *f)
574 {
575         struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
576         const struct soc_camera_format_xlate *xlate;
577         struct v4l2_pix_format *pix = &f->fmt.pix;
578         struct v4l2_subdev_format format = {
579                 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
580         };
581         struct v4l2_mbus_framefmt *mf = &format.format;
582         int ret;
583 
584         /* check with atmel-isi support format, if not support use YUYV */
585         if (!is_supported(icd, pix->pixelformat))
586                 pix->pixelformat = V4L2_PIX_FMT_YUYV;
587 
588         xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
589         if (!xlate) {
590                 dev_warn(icd->parent, "Format %x not found\n",
591                          pix->pixelformat);
592                 return -EINVAL;
593         }
594 
595         dev_dbg(icd->parent, "Plan to set format %dx%d\n",
596                         pix->width, pix->height);
597 
598         mf->width       = pix->width;
599         mf->height      = pix->height;
600         mf->field       = pix->field;
601         mf->colorspace  = pix->colorspace;
602         mf->code        = xlate->code;
603 
604         ret = v4l2_subdev_call(sd, pad, set_fmt, NULL, &format);
605         if (ret < 0)
606                 return ret;
607 
608         if (mf->code != xlate->code)
609                 return -EINVAL;
610 
611         pix->width              = mf->width;
612         pix->height             = mf->height;
613         pix->field              = mf->field;
614         pix->colorspace         = mf->colorspace;
615         icd->current_fmt        = xlate;
616 
617         dev_dbg(icd->parent, "Finally set format %dx%d\n",
618                 pix->width, pix->height);
619 
620         return ret;
621 }
622 
623 static int isi_camera_try_fmt(struct soc_camera_device *icd,
624                               struct v4l2_format *f)
625 {
626         struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
627         const struct soc_camera_format_xlate *xlate;
628         struct v4l2_pix_format *pix = &f->fmt.pix;
629         struct v4l2_subdev_pad_config pad_cfg;
630         struct v4l2_subdev_format format = {
631                 .which = V4L2_SUBDEV_FORMAT_TRY,
632         };
633         struct v4l2_mbus_framefmt *mf = &format.format;
634         u32 pixfmt = pix->pixelformat;
635         int ret;
636 
637         /* check with atmel-isi support format, if not support use YUYV */
638         if (!is_supported(icd, pix->pixelformat))
639                 pix->pixelformat = V4L2_PIX_FMT_YUYV;
640 
641         xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
642         if (pixfmt && !xlate) {
643                 dev_warn(icd->parent, "Format %x not found\n", pixfmt);
644                 return -EINVAL;
645         }
646 
647         /* limit to Atmel ISI hardware capabilities */
648         if (pix->height > MAX_SUPPORT_HEIGHT)
649                 pix->height = MAX_SUPPORT_HEIGHT;
650         if (pix->width > MAX_SUPPORT_WIDTH)
651                 pix->width = MAX_SUPPORT_WIDTH;
652 
653         /* limit to sensor capabilities */
654         mf->width       = pix->width;
655         mf->height      = pix->height;
656         mf->field       = pix->field;
657         mf->colorspace  = pix->colorspace;
658         mf->code        = xlate->code;
659 
660         ret = v4l2_subdev_call(sd, pad, set_fmt, &pad_cfg, &format);
661         if (ret < 0)
662                 return ret;
663 
664         pix->width      = mf->width;
665         pix->height     = mf->height;
666         pix->colorspace = mf->colorspace;
667 
668         switch (mf->field) {
669         case V4L2_FIELD_ANY:
670                 pix->field = V4L2_FIELD_NONE;
671                 break;
672         case V4L2_FIELD_NONE:
673                 break;
674         default:
675                 dev_err(icd->parent, "Field type %d unsupported.\n",
676                         mf->field);
677                 ret = -EINVAL;
678         }
679 
680         return ret;
681 }
682 
683 static const struct soc_mbus_pixelfmt isi_camera_formats[] = {
684         {
685                 .fourcc                 = V4L2_PIX_FMT_YUYV,
686                 .name                   = "Packed YUV422 16 bit",
687                 .bits_per_sample        = 8,
688                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
689                 .order                  = SOC_MBUS_ORDER_LE,
690                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
691         },
692         {
693                 .fourcc                 = V4L2_PIX_FMT_RGB565,
694                 .name                   = "RGB565",
695                 .bits_per_sample        = 8,
696                 .packing                = SOC_MBUS_PACKING_2X8_PADHI,
697                 .order                  = SOC_MBUS_ORDER_LE,
698                 .layout                 = SOC_MBUS_LAYOUT_PACKED,
699         },
700 };
701 
702 /* This will be corrected as we get more formats */
703 static bool isi_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
704 {
705         return  fmt->packing == SOC_MBUS_PACKING_NONE ||
706                 (fmt->bits_per_sample == 8 &&
707                  fmt->packing == SOC_MBUS_PACKING_2X8_PADHI) ||
708                 (fmt->bits_per_sample > 8 &&
709                  fmt->packing == SOC_MBUS_PACKING_EXTEND16);
710 }
711 
712 #define ISI_BUS_PARAM (V4L2_MBUS_MASTER |       \
713                 V4L2_MBUS_HSYNC_ACTIVE_HIGH |   \
714                 V4L2_MBUS_HSYNC_ACTIVE_LOW |    \
715                 V4L2_MBUS_VSYNC_ACTIVE_HIGH |   \
716                 V4L2_MBUS_VSYNC_ACTIVE_LOW |    \
717                 V4L2_MBUS_PCLK_SAMPLE_RISING |  \
718                 V4L2_MBUS_PCLK_SAMPLE_FALLING | \
719                 V4L2_MBUS_DATA_ACTIVE_HIGH)
720 
721 static int isi_camera_try_bus_param(struct soc_camera_device *icd,
722                                     unsigned char buswidth)
723 {
724         struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
725         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
726         struct atmel_isi *isi = ici->priv;
727         struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
728         unsigned long common_flags;
729         int ret;
730 
731         ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
732         if (!ret) {
733                 common_flags = soc_mbus_config_compatible(&cfg,
734                                                           ISI_BUS_PARAM);
735                 if (!common_flags) {
736                         dev_warn(icd->parent,
737                                  "Flags incompatible: camera 0x%x, host 0x%x\n",
738                                  cfg.flags, ISI_BUS_PARAM);
739                         return -EINVAL;
740                 }
741         } else if (ret != -ENOIOCTLCMD) {
742                 return ret;
743         }
744 
745         if ((1 << (buswidth - 1)) & isi->width_flags)
746                 return 0;
747         return -EINVAL;
748 }
749 
750 
751 static int isi_camera_get_formats(struct soc_camera_device *icd,
752                                   unsigned int idx,
753                                   struct soc_camera_format_xlate *xlate)
754 {
755         struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
756         int formats = 0, ret, i, n;
757         /* sensor format */
758         struct v4l2_subdev_mbus_code_enum code = {
759                 .which = V4L2_SUBDEV_FORMAT_ACTIVE,
760                 .index = idx,
761         };
762         /* soc camera host format */
763         const struct soc_mbus_pixelfmt *fmt;
764 
765         ret = v4l2_subdev_call(sd, pad, enum_mbus_code, NULL, &code);
766         if (ret < 0)
767                 /* No more formats */
768                 return 0;
769 
770         fmt = soc_mbus_get_fmtdesc(code.code);
771         if (!fmt) {
772                 dev_err(icd->parent,
773                         "Invalid format code #%u: %d\n", idx, code.code);
774                 return 0;
775         }
776 
777         /* This also checks support for the requested bits-per-sample */
778         ret = isi_camera_try_bus_param(icd, fmt->bits_per_sample);
779         if (ret < 0) {
780                 dev_err(icd->parent,
781                         "Fail to try the bus parameters.\n");
782                 return 0;
783         }
784 
785         switch (code.code) {
786         case MEDIA_BUS_FMT_UYVY8_2X8:
787         case MEDIA_BUS_FMT_VYUY8_2X8:
788         case MEDIA_BUS_FMT_YUYV8_2X8:
789         case MEDIA_BUS_FMT_YVYU8_2X8:
790                 n = ARRAY_SIZE(isi_camera_formats);
791                 formats += n;
792                 for (i = 0; xlate && i < n; i++, xlate++) {
793                         xlate->host_fmt = &isi_camera_formats[i];
794                         xlate->code     = code.code;
795                         dev_dbg(icd->parent, "Providing format %s using code %d\n",
796                                 xlate->host_fmt->name, xlate->code);
797                 }
798                 break;
799         default:
800                 if (!isi_camera_packing_supported(fmt))
801                         return 0;
802                 if (xlate)
803                         dev_dbg(icd->parent,
804                                 "Providing format %s in pass-through mode\n",
805                                 fmt->name);
806         }
807 
808         /* Generic pass-through */
809         formats++;
810         if (xlate) {
811                 xlate->host_fmt = fmt;
812                 xlate->code     = code.code;
813                 xlate++;
814         }
815 
816         return formats;
817 }
818 
819 static int isi_camera_add_device(struct soc_camera_device *icd)
820 {
821         dev_dbg(icd->parent, "Atmel ISI Camera driver attached to camera %d\n",
822                  icd->devnum);
823 
824         return 0;
825 }
826 
827 static void isi_camera_remove_device(struct soc_camera_device *icd)
828 {
829         dev_dbg(icd->parent, "Atmel ISI Camera driver detached from camera %d\n",
830                  icd->devnum);
831 }
832 
833 static unsigned int isi_camera_poll(struct file *file, poll_table *pt)
834 {
835         struct soc_camera_device *icd = file->private_data;
836 
837         return vb2_poll(&icd->vb2_vidq, file, pt);
838 }
839 
840 static int isi_camera_querycap(struct soc_camera_host *ici,
841                                struct v4l2_capability *cap)
842 {
843         strcpy(cap->driver, "atmel-isi");
844         strcpy(cap->card, "Atmel Image Sensor Interface");
845         cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
846         cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
847 
848         return 0;
849 }
850 
851 static int isi_camera_set_bus_param(struct soc_camera_device *icd)
852 {
853         struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
854         struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
855         struct atmel_isi *isi = ici->priv;
856         struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
857         unsigned long common_flags;
858         int ret;
859         u32 cfg1 = 0;
860 
861         ret = v4l2_subdev_call(sd, video, g_mbus_config, &cfg);
862         if (!ret) {
863                 common_flags = soc_mbus_config_compatible(&cfg,
864                                                           ISI_BUS_PARAM);
865                 if (!common_flags) {
866                         dev_warn(icd->parent,
867                                  "Flags incompatible: camera 0x%x, host 0x%x\n",
868                                  cfg.flags, ISI_BUS_PARAM);
869                         return -EINVAL;
870                 }
871         } else if (ret != -ENOIOCTLCMD) {
872                 return ret;
873         } else {
874                 common_flags = ISI_BUS_PARAM;
875         }
876         dev_dbg(icd->parent, "Flags cam: 0x%x host: 0x%x common: 0x%lx\n",
877                 cfg.flags, ISI_BUS_PARAM, common_flags);
878 
879         /* Make choises, based on platform preferences */
880         if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
881             (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
882                 if (isi->pdata.hsync_act_low)
883                         common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
884                 else
885                         common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
886         }
887 
888         if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
889             (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
890                 if (isi->pdata.vsync_act_low)
891                         common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
892                 else
893                         common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
894         }
895 
896         if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
897             (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
898                 if (isi->pdata.pclk_act_falling)
899                         common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
900                 else
901                         common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
902         }
903 
904         cfg.flags = common_flags;
905         ret = v4l2_subdev_call(sd, video, s_mbus_config, &cfg);
906         if (ret < 0 && ret != -ENOIOCTLCMD) {
907                 dev_dbg(icd->parent, "camera s_mbus_config(0x%lx) returned %d\n",
908                         common_flags, ret);
909                 return ret;
910         }
911 
912         /* set bus param for ISI */
913         if (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
914                 cfg1 |= ISI_CFG1_HSYNC_POL_ACTIVE_LOW;
915         if (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
916                 cfg1 |= ISI_CFG1_VSYNC_POL_ACTIVE_LOW;
917         if (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
918                 cfg1 |= ISI_CFG1_PIXCLK_POL_ACTIVE_FALLING;
919 
920         dev_dbg(icd->parent, "vsync active %s, hsync active %s, sampling on pix clock %s edge\n",
921                 common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW ? "low" : "high",
922                 common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW ? "low" : "high",
923                 common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING ? "falling" : "rising");
924 
925         if (isi->pdata.has_emb_sync)
926                 cfg1 |= ISI_CFG1_EMB_SYNC;
927         if (isi->pdata.full_mode)
928                 cfg1 |= ISI_CFG1_FULL_MODE;
929 
930         cfg1 |= ISI_CFG1_THMASK_BEATS_16;
931 
932         /* Enable PM and peripheral clock before operate isi registers */
933         pm_runtime_get_sync(ici->v4l2_dev.dev);
934 
935         isi_writel(isi, ISI_CTRL, ISI_CTRL_DIS);
936         isi_writel(isi, ISI_CFG1, cfg1);
937 
938         pm_runtime_put(ici->v4l2_dev.dev);
939 
940         return 0;
941 }
942 
943 static struct soc_camera_host_ops isi_soc_camera_host_ops = {
944         .owner          = THIS_MODULE,
945         .add            = isi_camera_add_device,
946         .remove         = isi_camera_remove_device,
947         .set_fmt        = isi_camera_set_fmt,
948         .try_fmt        = isi_camera_try_fmt,
949         .get_formats    = isi_camera_get_formats,
950         .init_videobuf2 = isi_camera_init_videobuf,
951         .poll           = isi_camera_poll,
952         .querycap       = isi_camera_querycap,
953         .set_bus_param  = isi_camera_set_bus_param,
954 };
955 
956 /* -----------------------------------------------------------------------*/
957 static int atmel_isi_remove(struct platform_device *pdev)
958 {
959         struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
960         struct atmel_isi *isi = container_of(soc_host,
961                                         struct atmel_isi, soc_host);
962 
963         soc_camera_host_unregister(soc_host);
964         dma_free_coherent(&pdev->dev,
965                         sizeof(struct fbd) * MAX_BUFFER_NUM,
966                         isi->p_fb_descriptors,
967                         isi->fb_descriptors_phys);
968         pm_runtime_disable(&pdev->dev);
969 
970         return 0;
971 }
972 
973 static int atmel_isi_parse_dt(struct atmel_isi *isi,
974                         struct platform_device *pdev)
975 {
976         struct device_node *np= pdev->dev.of_node;
977         struct v4l2_of_endpoint ep;
978         int err;
979 
980         /* Default settings for ISI */
981         isi->pdata.full_mode = 1;
982         isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL;
983 
984         np = of_graph_get_next_endpoint(np, NULL);
985         if (!np) {
986                 dev_err(&pdev->dev, "Could not find the endpoint\n");
987                 return -EINVAL;
988         }
989 
990         err = v4l2_of_parse_endpoint(np, &ep);
991         of_node_put(np);
992         if (err) {
993                 dev_err(&pdev->dev, "Could not parse the endpoint\n");
994                 return err;
995         }
996 
997         switch (ep.bus.parallel.bus_width) {
998         case 8:
999                 isi->pdata.data_width_flags = ISI_DATAWIDTH_8;
1000                 break;
1001         case 10:
1002                 isi->pdata.data_width_flags =
1003                                 ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10;
1004                 break;
1005         default:
1006                 dev_err(&pdev->dev, "Unsupported bus width: %d\n",
1007                                 ep.bus.parallel.bus_width);
1008                 return -EINVAL;
1009         }
1010 
1011         if (ep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
1012                 isi->pdata.hsync_act_low = true;
1013         if (ep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
1014                 isi->pdata.vsync_act_low = true;
1015         if (ep.bus.parallel.flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
1016                 isi->pdata.pclk_act_falling = true;
1017 
1018         if (ep.bus_type == V4L2_MBUS_BT656)
1019                 isi->pdata.has_emb_sync = true;
1020 
1021         return 0;
1022 }
1023 
1024 static int atmel_isi_probe(struct platform_device *pdev)
1025 {
1026         int irq;
1027         struct atmel_isi *isi;
1028         struct resource *regs;
1029         int ret, i;
1030         struct soc_camera_host *soc_host;
1031 
1032         isi = devm_kzalloc(&pdev->dev, sizeof(struct atmel_isi), GFP_KERNEL);
1033         if (!isi) {
1034                 dev_err(&pdev->dev, "Can't allocate interface!\n");
1035                 return -ENOMEM;
1036         }
1037 
1038         isi->pclk = devm_clk_get(&pdev->dev, "isi_clk");
1039         if (IS_ERR(isi->pclk))
1040                 return PTR_ERR(isi->pclk);
1041 
1042         ret = atmel_isi_parse_dt(isi, pdev);
1043         if (ret)
1044                 return ret;
1045 
1046         isi->active = NULL;
1047         spin_lock_init(&isi->lock);
1048         INIT_LIST_HEAD(&isi->video_buffer_list);
1049         INIT_LIST_HEAD(&isi->dma_desc_head);
1050 
1051         isi->p_fb_descriptors = dma_alloc_coherent(&pdev->dev,
1052                                 sizeof(struct fbd) * MAX_BUFFER_NUM,
1053                                 &isi->fb_descriptors_phys,
1054                                 GFP_KERNEL);
1055         if (!isi->p_fb_descriptors) {
1056                 dev_err(&pdev->dev, "Can't allocate descriptors!\n");
1057                 return -ENOMEM;
1058         }
1059 
1060         for (i = 0; i < MAX_BUFFER_NUM; i++) {
1061                 isi->dma_desc[i].p_fbd = isi->p_fb_descriptors + i;
1062                 isi->dma_desc[i].fbd_phys = isi->fb_descriptors_phys +
1063                                         i * sizeof(struct fbd);
1064                 list_add(&isi->dma_desc[i].list, &isi->dma_desc_head);
1065         }
1066 
1067         regs = platform_get_resource(pdev, IORESOURCE_MEM, 0);
1068         isi->regs = devm_ioremap_resource(&pdev->dev, regs);
1069         if (IS_ERR(isi->regs)) {
1070                 ret = PTR_ERR(isi->regs);
1071                 goto err_ioremap;
1072         }
1073 
1074         if (isi->pdata.data_width_flags & ISI_DATAWIDTH_8)
1075                 isi->width_flags = 1 << 7;
1076         if (isi->pdata.data_width_flags & ISI_DATAWIDTH_10)
1077                 isi->width_flags |= 1 << 9;
1078 
1079         irq = platform_get_irq(pdev, 0);
1080         if (irq < 0) {
1081                 ret = irq;
1082                 goto err_req_irq;
1083         }
1084 
1085         ret = devm_request_irq(&pdev->dev, irq, isi_interrupt, 0, "isi", isi);
1086         if (ret) {
1087                 dev_err(&pdev->dev, "Unable to request irq %d\n", irq);
1088                 goto err_req_irq;
1089         }
1090         isi->irq = irq;
1091 
1092         soc_host                = &isi->soc_host;
1093         soc_host->drv_name      = "isi-camera";
1094         soc_host->ops           = &isi_soc_camera_host_ops;
1095         soc_host->priv          = isi;
1096         soc_host->v4l2_dev.dev  = &pdev->dev;
1097         soc_host->nr            = pdev->id;
1098 
1099         pm_suspend_ignore_children(&pdev->dev, true);
1100         pm_runtime_enable(&pdev->dev);
1101 
1102         ret = soc_camera_host_register(soc_host);
1103         if (ret) {
1104                 dev_err(&pdev->dev, "Unable to register soc camera host\n");
1105                 goto err_register_soc_camera_host;
1106         }
1107         return 0;
1108 
1109 err_register_soc_camera_host:
1110         pm_runtime_disable(&pdev->dev);
1111 err_req_irq:
1112 err_ioremap:
1113         dma_free_coherent(&pdev->dev,
1114                         sizeof(struct fbd) * MAX_BUFFER_NUM,
1115                         isi->p_fb_descriptors,
1116                         isi->fb_descriptors_phys);
1117 
1118         return ret;
1119 }
1120 
1121 #ifdef CONFIG_PM
1122 static int atmel_isi_runtime_suspend(struct device *dev)
1123 {
1124         struct soc_camera_host *soc_host = to_soc_camera_host(dev);
1125         struct atmel_isi *isi = container_of(soc_host,
1126                                         struct atmel_isi, soc_host);
1127 
1128         clk_disable_unprepare(isi->pclk);
1129 
1130         return 0;
1131 }
1132 static int atmel_isi_runtime_resume(struct device *dev)
1133 {
1134         struct soc_camera_host *soc_host = to_soc_camera_host(dev);
1135         struct atmel_isi *isi = container_of(soc_host,
1136                                         struct atmel_isi, soc_host);
1137 
1138         return clk_prepare_enable(isi->pclk);
1139 }
1140 #endif /* CONFIG_PM */
1141 
1142 static const struct dev_pm_ops atmel_isi_dev_pm_ops = {
1143         SET_RUNTIME_PM_OPS(atmel_isi_runtime_suspend,
1144                                 atmel_isi_runtime_resume, NULL)
1145 };
1146 
1147 static const struct of_device_id atmel_isi_of_match[] = {
1148         { .compatible = "atmel,at91sam9g45-isi" },
1149         { }
1150 };
1151 MODULE_DEVICE_TABLE(of, atmel_isi_of_match);
1152 
1153 static struct platform_driver atmel_isi_driver = {
1154         .remove         = atmel_isi_remove,
1155         .driver         = {
1156                 .name = "atmel_isi",
1157                 .of_match_table = of_match_ptr(atmel_isi_of_match),
1158                 .pm     = &atmel_isi_dev_pm_ops,
1159         },
1160 };
1161 
1162 module_platform_driver_probe(atmel_isi_driver, atmel_isi_probe);
1163 
1164 MODULE_AUTHOR("Josh Wu <josh.wu@atmel.com>");
1165 MODULE_DESCRIPTION("The V4L2 driver for Atmel Linux");
1166 MODULE_LICENSE("GPL");
1167 MODULE_SUPPORTED_DEVICE("video");
1168 

This page was automatically generated by LXR 0.3.1 (source).  •  Linux is a registered trademark of Linus Torvalds  •  Contact us