aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/s5p-fimc/mipi-csis.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/s5p-fimc/mipi-csis.c')
-rw-r--r--drivers/media/platform/s5p-fimc/mipi-csis.c75
1 files changed, 62 insertions, 13 deletions
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
index e92236ac5cfe..4c961b1b68e6 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.c
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
@@ -2,7 +2,7 @@
2 * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver 2 * Samsung S5P/EXYNOS4 SoC series MIPI-CSI receiver driver
3 * 3 *
4 * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd. 4 * Copyright (C) 2011 - 2012 Samsung Electronics Co., Ltd.
5 * Sylwester Nawrocki, <s.nawrocki@samsung.com> 5 * Sylwester Nawrocki <s.nawrocki@samsung.com>
6 * 6 *
7 * This program is free software; you can redistribute it and/or modify 7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as 8 * it under the terms of the GNU General Public License version 2 as
@@ -98,6 +98,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-2)");
98#define CSIS_MAX_PIX_WIDTH 0xffff 98#define CSIS_MAX_PIX_WIDTH 0xffff
99#define CSIS_MAX_PIX_HEIGHT 0xffff 99#define CSIS_MAX_PIX_HEIGHT 0xffff
100 100
101/* Non-image packet data buffers */
102#define S5PCSIS_PKTDATA_ODD 0x2000
103#define S5PCSIS_PKTDATA_EVEN 0x3000
104#define S5PCSIS_PKTDATA_SIZE SZ_4K
105
101enum { 106enum {
102 CSIS_CLK_MUX, 107 CSIS_CLK_MUX,
103 CSIS_CLK_GATE, 108 CSIS_CLK_GATE,
@@ -110,8 +115,8 @@ static char *csi_clock_name[] = {
110#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name) 115#define NUM_CSIS_CLOCKS ARRAY_SIZE(csi_clock_name)
111 116
112static const char * const csis_supply_name[] = { 117static const char * const csis_supply_name[] = {
113 "vdd11", /* 1.1V or 1.2V (s5pc100) MIPI CSI suppply */ 118 "vddcore", /* CSIS Core (1.0V, 1.1V or 1.2V) suppply */
114 "vdd18", /* VDD 1.8V and MIPI CSI PLL supply */ 119 "vddio", /* CSIS I/O and PLL (1.8V) supply */
115}; 120};
116#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name) 121#define CSIS_NUM_SUPPLIES ARRAY_SIZE(csis_supply_name)
117 122
@@ -144,12 +149,18 @@ static const struct s5pcsis_event s5pcsis_events[] = {
144}; 149};
145#define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events) 150#define S5PCSIS_NUM_EVENTS ARRAY_SIZE(s5pcsis_events)
146 151
152struct csis_pktbuf {
153 u32 *data;
154 unsigned int len;
155};
156
147/** 157/**
148 * struct csis_state - the driver's internal state data structure 158 * struct csis_state - the driver's internal state data structure
149 * @lock: mutex serializing the subdev and power management operations, 159 * @lock: mutex serializing the subdev and power management operations,
150 * protecting @format and @flags members 160 * protecting @format and @flags members
151 * @pads: CSIS pads array 161 * @pads: CSIS pads array
152 * @sd: v4l2_subdev associated with CSIS device instance 162 * @sd: v4l2_subdev associated with CSIS device instance
163 * @index: the hardware instance index
153 * @pdev: CSIS platform device 164 * @pdev: CSIS platform device
154 * @regs: mmaped I/O registers memory 165 * @regs: mmaped I/O registers memory
155 * @supplies: CSIS regulator supplies 166 * @supplies: CSIS regulator supplies
@@ -159,12 +170,14 @@ static const struct s5pcsis_event s5pcsis_events[] = {
159 * @csis_fmt: current CSIS pixel format 170 * @csis_fmt: current CSIS pixel format
160 * @format: common media bus format for the source and sink pad 171 * @format: common media bus format for the source and sink pad
161 * @slock: spinlock protecting structure members below 172 * @slock: spinlock protecting structure members below
173 * @pkt_buf: the frame embedded (non-image) data buffer
162 * @events: MIPI-CSIS event (error) counters 174 * @events: MIPI-CSIS event (error) counters
163 */ 175 */
164struct csis_state { 176struct csis_state {
165 struct mutex lock; 177 struct mutex lock;
166 struct media_pad pads[CSIS_PADS_NUM]; 178 struct media_pad pads[CSIS_PADS_NUM];
167 struct v4l2_subdev sd; 179 struct v4l2_subdev sd;
180 u8 index;
168 struct platform_device *pdev; 181 struct platform_device *pdev;
169 void __iomem *regs; 182 void __iomem *regs;
170 struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES]; 183 struct regulator_bulk_data supplies[CSIS_NUM_SUPPLIES];
@@ -175,6 +188,7 @@ struct csis_state {
175 struct v4l2_mbus_framefmt format; 188 struct v4l2_mbus_framefmt format;
176 189
177 struct spinlock slock; 190 struct spinlock slock;
191 struct csis_pktbuf pkt_buf;
178 struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; 192 struct s5pcsis_event events[S5PCSIS_NUM_EVENTS];
179}; 193};
180 194
@@ -202,7 +216,11 @@ static const struct csis_pix_format s5pcsis_formats[] = {
202 .code = V4L2_MBUS_FMT_JPEG_1X8, 216 .code = V4L2_MBUS_FMT_JPEG_1X8,
203 .fmt_reg = S5PCSIS_CFG_FMT_USER(1), 217 .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
204 .data_alignment = 32, 218 .data_alignment = 32,
205 }, 219 }, {
220 .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8,
221 .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
222 .data_alignment = 32,
223 }
206}; 224};
207 225
208#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r) 226#define s5pcsis_write(__csis, __r, __v) writel(__v, __csis->regs + __r)
@@ -266,7 +284,7 @@ static void __s5pcsis_set_format(struct csis_state *state)
266 struct v4l2_mbus_framefmt *mf = &state->format; 284 struct v4l2_mbus_framefmt *mf = &state->format;
267 u32 val; 285 u32 val;
268 286
269 v4l2_dbg(1, debug, &state->sd, "fmt: %d, %d x %d\n", 287 v4l2_dbg(1, debug, &state->sd, "fmt: %#x, %d x %d\n",
270 mf->code, mf->width, mf->height); 288 mf->code, mf->width, mf->height);
271 289
272 /* Color format */ 290 /* Color format */
@@ -304,8 +322,10 @@ static void s5pcsis_set_params(struct csis_state *state)
304 val |= S5PCSIS_CTRL_ALIGN_32BIT; 322 val |= S5PCSIS_CTRL_ALIGN_32BIT;
305 else /* 24-bits */ 323 else /* 24-bits */
306 val &= ~S5PCSIS_CTRL_ALIGN_32BIT; 324 val &= ~S5PCSIS_CTRL_ALIGN_32BIT;
307 /* Not using external clock. */ 325
308 val &= ~S5PCSIS_CTRL_WCLK_EXTCLK; 326 val &= ~S5PCSIS_CTRL_WCLK_EXTCLK;
327 if (pdata->wclk_source)
328 val |= S5PCSIS_CTRL_WCLK_EXTCLK;
309 s5pcsis_write(state, S5PCSIS_CTRL, val); 329 s5pcsis_write(state, S5PCSIS_CTRL, val);
310 330
311 /* Update the shadow register. */ 331 /* Update the shadow register. */
@@ -529,6 +549,22 @@ static int s5pcsis_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
529 return 0; 549 return 0;
530} 550}
531 551
552static int s5pcsis_s_rx_buffer(struct v4l2_subdev *sd, void *buf,
553 unsigned int *size)
554{
555 struct csis_state *state = sd_to_csis_state(sd);
556 unsigned long flags;
557
558 *size = min_t(unsigned int, *size, S5PCSIS_PKTDATA_SIZE);
559
560 spin_lock_irqsave(&state->slock, flags);
561 state->pkt_buf.data = buf;
562 state->pkt_buf.len = *size;
563 spin_unlock_irqrestore(&state->slock, flags);
564
565 return 0;
566}
567
532static int s5pcsis_log_status(struct v4l2_subdev *sd) 568static int s5pcsis_log_status(struct v4l2_subdev *sd)
533{ 569{
534 struct csis_state *state = sd_to_csis_state(sd); 570 struct csis_state *state = sd_to_csis_state(sd);
@@ -566,6 +602,7 @@ static struct v4l2_subdev_pad_ops s5pcsis_pad_ops = {
566}; 602};
567 603
568static struct v4l2_subdev_video_ops s5pcsis_video_ops = { 604static struct v4l2_subdev_video_ops s5pcsis_video_ops = {
605 .s_rx_buffer = s5pcsis_s_rx_buffer,
569 .s_stream = s5pcsis_s_stream, 606 .s_stream = s5pcsis_s_stream,
570}; 607};
571 608
@@ -578,13 +615,26 @@ static struct v4l2_subdev_ops s5pcsis_subdev_ops = {
578static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id) 615static irqreturn_t s5pcsis_irq_handler(int irq, void *dev_id)
579{ 616{
580 struct csis_state *state = dev_id; 617 struct csis_state *state = dev_id;
618 struct csis_pktbuf *pktbuf = &state->pkt_buf;
581 unsigned long flags; 619 unsigned long flags;
582 u32 status; 620 u32 status;
583 621
584 status = s5pcsis_read(state, S5PCSIS_INTSRC); 622 status = s5pcsis_read(state, S5PCSIS_INTSRC);
585
586 spin_lock_irqsave(&state->slock, flags); 623 spin_lock_irqsave(&state->slock, flags);
587 624
625 if ((status & S5PCSIS_INTSRC_NON_IMAGE_DATA) && pktbuf->data) {
626 u32 offset;
627
628 if (status & S5PCSIS_INTSRC_EVEN)
629 offset = S5PCSIS_PKTDATA_EVEN;
630 else
631 offset = S5PCSIS_PKTDATA_ODD;
632
633 memcpy(pktbuf->data, state->regs + offset, pktbuf->len);
634 pktbuf->data = NULL;
635 rmb();
636 }
637
588 /* Update the event/error counters */ 638 /* Update the event/error counters */
589 if ((status & S5PCSIS_INTSRC_ERRORS) || debug) { 639 if ((status & S5PCSIS_INTSRC_ERRORS) || debug) {
590 int i; 640 int i;
@@ -620,14 +670,15 @@ static int __devinit s5pcsis_probe(struct platform_device *pdev)
620 spin_lock_init(&state->slock); 670 spin_lock_init(&state->slock);
621 671
622 state->pdev = pdev; 672 state->pdev = pdev;
673 state->index = max(0, pdev->id);
623 674
624 pdata = pdev->dev.platform_data; 675 pdata = pdev->dev.platform_data;
625 if (pdata == NULL || pdata->phy_enable == NULL) { 676 if (pdata == NULL) {
626 dev_err(&pdev->dev, "Platform data not fully specified\n"); 677 dev_err(&pdev->dev, "Platform data not fully specified\n");
627 return -EINVAL; 678 return -EINVAL;
628 } 679 }
629 680
630 if ((pdev->id == 1 && pdata->lanes > CSIS1_MAX_LANES) || 681 if ((state->index == 1 && pdata->lanes > CSIS1_MAX_LANES) ||
631 pdata->lanes > CSIS0_MAX_LANES) { 682 pdata->lanes > CSIS0_MAX_LANES) {
632 dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n", 683 dev_err(&pdev->dev, "Unsupported number of data lanes: %d\n",
633 pdata->lanes); 684 pdata->lanes);
@@ -710,7 +761,6 @@ e_clkput:
710 761
711static int s5pcsis_pm_suspend(struct device *dev, bool runtime) 762static int s5pcsis_pm_suspend(struct device *dev, bool runtime)
712{ 763{
713 struct s5p_platform_mipi_csis *pdata = dev->platform_data;
714 struct platform_device *pdev = to_platform_device(dev); 764 struct platform_device *pdev = to_platform_device(dev);
715 struct v4l2_subdev *sd = platform_get_drvdata(pdev); 765 struct v4l2_subdev *sd = platform_get_drvdata(pdev);
716 struct csis_state *state = sd_to_csis_state(sd); 766 struct csis_state *state = sd_to_csis_state(sd);
@@ -722,7 +772,7 @@ static int s5pcsis_pm_suspend(struct device *dev, bool runtime)
722 mutex_lock(&state->lock); 772 mutex_lock(&state->lock);
723 if (state->flags & ST_POWERED) { 773 if (state->flags & ST_POWERED) {
724 s5pcsis_stop_stream(state); 774 s5pcsis_stop_stream(state);
725 ret = pdata->phy_enable(state->pdev, false); 775 ret = s5p_csis_phy_enable(state->index, false);
726 if (ret) 776 if (ret)
727 goto unlock; 777 goto unlock;
728 ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES, 778 ret = regulator_bulk_disable(CSIS_NUM_SUPPLIES,
@@ -741,7 +791,6 @@ static int s5pcsis_pm_suspend(struct device *dev, bool runtime)
741 791
742static int s5pcsis_pm_resume(struct device *dev, bool runtime) 792static int s5pcsis_pm_resume(struct device *dev, bool runtime)
743{ 793{
744 struct s5p_platform_mipi_csis *pdata = dev->platform_data;
745 struct platform_device *pdev = to_platform_device(dev); 794 struct platform_device *pdev = to_platform_device(dev);
746 struct v4l2_subdev *sd = platform_get_drvdata(pdev); 795 struct v4l2_subdev *sd = platform_get_drvdata(pdev);
747 struct csis_state *state = sd_to_csis_state(sd); 796 struct csis_state *state = sd_to_csis_state(sd);
@@ -759,7 +808,7 @@ static int s5pcsis_pm_resume(struct device *dev, bool runtime)
759 state->supplies); 808 state->supplies);
760 if (ret) 809 if (ret)
761 goto unlock; 810 goto unlock;
762 ret = pdata->phy_enable(state->pdev, true); 811 ret = s5p_csis_phy_enable(state->index, true);
763 if (!ret) { 812 if (!ret) {
764 state->flags |= ST_POWERED; 813 state->flags |= ST_POWERED;
765 } else { 814 } else {