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.c101
1 files changed, 76 insertions, 25 deletions
diff --git a/drivers/media/platform/s5p-fimc/mipi-csis.c b/drivers/media/platform/s5p-fimc/mipi-csis.c
index 7abae012f55e..981863d05aaa 100644
--- a/drivers/media/platform/s5p-fimc/mipi-csis.c
+++ b/drivers/media/platform/s5p-fimc/mipi-csis.c
@@ -187,7 +187,7 @@ struct csis_state {
187 const struct csis_pix_format *csis_fmt; 187 const struct csis_pix_format *csis_fmt;
188 struct v4l2_mbus_framefmt format; 188 struct v4l2_mbus_framefmt format;
189 189
190 struct spinlock slock; 190 spinlock_t slock;
191 struct csis_pktbuf pkt_buf; 191 struct csis_pktbuf pkt_buf;
192 struct s5pcsis_event events[S5PCSIS_NUM_EVENTS]; 192 struct s5pcsis_event events[S5PCSIS_NUM_EVENTS];
193}; 193};
@@ -220,6 +220,18 @@ static const struct csis_pix_format s5pcsis_formats[] = {
220 .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8, 220 .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8,
221 .fmt_reg = S5PCSIS_CFG_FMT_USER(1), 221 .fmt_reg = S5PCSIS_CFG_FMT_USER(1),
222 .data_alignment = 32, 222 .data_alignment = 32,
223 }, {
224 .code = V4L2_MBUS_FMT_SGRBG8_1X8,
225 .fmt_reg = S5PCSIS_CFG_FMT_RAW8,
226 .data_alignment = 24,
227 }, {
228 .code = V4L2_MBUS_FMT_SGRBG10_1X10,
229 .fmt_reg = S5PCSIS_CFG_FMT_RAW10,
230 .data_alignment = 24,
231 }, {
232 .code = V4L2_MBUS_FMT_SGRBG12_1X12,
233 .fmt_reg = S5PCSIS_CFG_FMT_RAW12,
234 .data_alignment = 24,
223 } 235 }
224}; 236};
225 237
@@ -261,7 +273,8 @@ static void s5pcsis_reset(struct csis_state *state)
261 273
262static void s5pcsis_system_enable(struct csis_state *state, int on) 274static void s5pcsis_system_enable(struct csis_state *state, int on)
263{ 275{
264 u32 val; 276 struct s5p_platform_mipi_csis *pdata = state->pdev->dev.platform_data;
277 u32 val, mask;
265 278
266 val = s5pcsis_read(state, S5PCSIS_CTRL); 279 val = s5pcsis_read(state, S5PCSIS_CTRL);
267 if (on) 280 if (on)
@@ -271,10 +284,11 @@ static void s5pcsis_system_enable(struct csis_state *state, int on)
271 s5pcsis_write(state, S5PCSIS_CTRL, val); 284 s5pcsis_write(state, S5PCSIS_CTRL, val);
272 285
273 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL); 286 val = s5pcsis_read(state, S5PCSIS_DPHYCTRL);
274 if (on) 287 val &= ~S5PCSIS_DPHYCTRL_ENABLE;
275 val |= S5PCSIS_DPHYCTRL_ENABLE; 288 if (on) {
276 else 289 mask = (1 << (pdata->lanes + 1)) - 1;
277 val &= ~S5PCSIS_DPHYCTRL_ENABLE; 290 val |= (mask & S5PCSIS_DPHYCTRL_ENABLE);
291 }
278 s5pcsis_write(state, S5PCSIS_DPHYCTRL, val); 292 s5pcsis_write(state, S5PCSIS_DPHYCTRL, val);
279} 293}
280 294
@@ -338,11 +352,11 @@ static void s5pcsis_clk_put(struct csis_state *state)
338 int i; 352 int i;
339 353
340 for (i = 0; i < NUM_CSIS_CLOCKS; i++) { 354 for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
341 if (IS_ERR_OR_NULL(state->clock[i])) 355 if (IS_ERR(state->clock[i]))
342 continue; 356 continue;
343 clk_unprepare(state->clock[i]); 357 clk_unprepare(state->clock[i]);
344 clk_put(state->clock[i]); 358 clk_put(state->clock[i]);
345 state->clock[i] = NULL; 359 state->clock[i] = ERR_PTR(-EINVAL);
346 } 360 }
347} 361}
348 362
@@ -351,14 +365,19 @@ static int s5pcsis_clk_get(struct csis_state *state)
351 struct device *dev = &state->pdev->dev; 365 struct device *dev = &state->pdev->dev;
352 int i, ret; 366 int i, ret;
353 367
368 for (i = 0; i < NUM_CSIS_CLOCKS; i++)
369 state->clock[i] = ERR_PTR(-EINVAL);
370
354 for (i = 0; i < NUM_CSIS_CLOCKS; i++) { 371 for (i = 0; i < NUM_CSIS_CLOCKS; i++) {
355 state->clock[i] = clk_get(dev, csi_clock_name[i]); 372 state->clock[i] = clk_get(dev, csi_clock_name[i]);
356 if (IS_ERR(state->clock[i])) 373 if (IS_ERR(state->clock[i])) {
374 ret = PTR_ERR(state->clock[i]);
357 goto err; 375 goto err;
376 }
358 ret = clk_prepare(state->clock[i]); 377 ret = clk_prepare(state->clock[i]);
359 if (ret < 0) { 378 if (ret < 0) {
360 clk_put(state->clock[i]); 379 clk_put(state->clock[i]);
361 state->clock[i] = NULL; 380 state->clock[i] = ERR_PTR(-EINVAL);
362 goto err; 381 goto err;
363 } 382 }
364 } 383 }
@@ -366,7 +385,31 @@ static int s5pcsis_clk_get(struct csis_state *state)
366err: 385err:
367 s5pcsis_clk_put(state); 386 s5pcsis_clk_put(state);
368 dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]); 387 dev_err(dev, "failed to get clock: %s\n", csi_clock_name[i]);
369 return -ENXIO; 388 return ret;
389}
390
391static void dump_regs(struct csis_state *state, const char *label)
392{
393 struct {
394 u32 offset;
395 const char * const name;
396 } registers[] = {
397 { 0x00, "CTRL" },
398 { 0x04, "DPHYCTRL" },
399 { 0x08, "CONFIG" },
400 { 0x0c, "DPHYSTS" },
401 { 0x10, "INTMSK" },
402 { 0x2c, "RESOL" },
403 { 0x38, "SDW_CONFIG" },
404 };
405 u32 i;
406
407 v4l2_info(&state->sd, "--- %s ---\n", label);
408
409 for (i = 0; i < ARRAY_SIZE(registers); i++) {
410 u32 cfg = s5pcsis_read(state, registers[i].offset);
411 v4l2_info(&state->sd, "%10s: 0x%08x\n", registers[i].name, cfg);
412 }
370} 413}
371 414
372static void s5pcsis_start_stream(struct csis_state *state) 415static void s5pcsis_start_stream(struct csis_state *state)
@@ -401,12 +444,12 @@ static void s5pcsis_log_counters(struct csis_state *state, bool non_errors)
401 444
402 spin_lock_irqsave(&state->slock, flags); 445 spin_lock_irqsave(&state->slock, flags);
403 446
404 for (i--; i >= 0; i--) 447 for (i--; i >= 0; i--) {
405 if (state->events[i].counter >= 0) 448 if (state->events[i].counter > 0 || debug)
406 v4l2_info(&state->sd, "%s events: %d\n", 449 v4l2_info(&state->sd, "%s events: %d\n",
407 state->events[i].name, 450 state->events[i].name,
408 state->events[i].counter); 451 state->events[i].counter);
409 452 }
410 spin_unlock_irqrestore(&state->slock, flags); 453 spin_unlock_irqrestore(&state->slock, flags);
411} 454}
412 455
@@ -569,7 +612,11 @@ static int s5pcsis_log_status(struct v4l2_subdev *sd)
569{ 612{
570 struct csis_state *state = sd_to_csis_state(sd); 613 struct csis_state *state = sd_to_csis_state(sd);
571 614
615 mutex_lock(&state->lock);
572 s5pcsis_log_counters(state, true); 616 s5pcsis_log_counters(state, true);
617 if (debug && (state->flags & ST_POWERED))
618 dump_regs(state, __func__);
619 mutex_unlock(&state->lock);
573 return 0; 620 return 0;
574} 621}
575 622
@@ -699,26 +746,32 @@ static int s5pcsis_probe(struct platform_device *pdev)
699 for (i = 0; i < CSIS_NUM_SUPPLIES; i++) 746 for (i = 0; i < CSIS_NUM_SUPPLIES; i++)
700 state->supplies[i].supply = csis_supply_name[i]; 747 state->supplies[i].supply = csis_supply_name[i];
701 748
702 ret = regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES, 749 ret = devm_regulator_bulk_get(&pdev->dev, CSIS_NUM_SUPPLIES,
703 state->supplies); 750 state->supplies);
704 if (ret) 751 if (ret)
705 return ret; 752 return ret;
706 753
707 ret = s5pcsis_clk_get(state); 754 ret = s5pcsis_clk_get(state);
708 if (ret) 755 if (ret < 0)
709 goto e_clkput; 756 return ret;
710 757
711 clk_enable(state->clock[CSIS_CLK_MUX]);
712 if (pdata->clk_rate) 758 if (pdata->clk_rate)
713 clk_set_rate(state->clock[CSIS_CLK_MUX], pdata->clk_rate); 759 ret = clk_set_rate(state->clock[CSIS_CLK_MUX],
760 pdata->clk_rate);
714 else 761 else
715 dev_WARN(&pdev->dev, "No clock frequency specified!\n"); 762 dev_WARN(&pdev->dev, "No clock frequency specified!\n");
763 if (ret < 0)
764 goto e_clkput;
765
766 ret = clk_enable(state->clock[CSIS_CLK_MUX]);
767 if (ret < 0)
768 goto e_clkput;
716 769
717 ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler, 770 ret = devm_request_irq(&pdev->dev, state->irq, s5pcsis_irq_handler,
718 0, dev_name(&pdev->dev), state); 771 0, dev_name(&pdev->dev), state);
719 if (ret) { 772 if (ret) {
720 dev_err(&pdev->dev, "Interrupt request failed\n"); 773 dev_err(&pdev->dev, "Interrupt request failed\n");
721 goto e_regput; 774 goto e_clkdis;
722 } 775 }
723 776
724 v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops); 777 v4l2_subdev_init(&state->sd, &s5pcsis_subdev_ops);
@@ -736,7 +789,7 @@ static int s5pcsis_probe(struct platform_device *pdev)
736 ret = media_entity_init(&state->sd.entity, 789 ret = media_entity_init(&state->sd.entity,
737 CSIS_PADS_NUM, state->pads, 0); 790 CSIS_PADS_NUM, state->pads, 0);
738 if (ret < 0) 791 if (ret < 0)
739 goto e_clkput; 792 goto e_clkdis;
740 793
741 /* This allows to retrieve the platform device id by the host driver */ 794 /* This allows to retrieve the platform device id by the host driver */
742 v4l2_set_subdevdata(&state->sd, pdev); 795 v4l2_set_subdevdata(&state->sd, pdev);
@@ -749,10 +802,9 @@ static int s5pcsis_probe(struct platform_device *pdev)
749 pm_runtime_enable(&pdev->dev); 802 pm_runtime_enable(&pdev->dev);
750 return 0; 803 return 0;
751 804
752e_regput: 805e_clkdis:
753 regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
754e_clkput:
755 clk_disable(state->clock[CSIS_CLK_MUX]); 806 clk_disable(state->clock[CSIS_CLK_MUX]);
807e_clkput:
756 s5pcsis_clk_put(state); 808 s5pcsis_clk_put(state);
757 return ret; 809 return ret;
758} 810}
@@ -859,7 +911,6 @@ static int s5pcsis_remove(struct platform_device *pdev)
859 clk_disable(state->clock[CSIS_CLK_MUX]); 911 clk_disable(state->clock[CSIS_CLK_MUX]);
860 pm_runtime_set_suspended(&pdev->dev); 912 pm_runtime_set_suspended(&pdev->dev);
861 s5pcsis_clk_put(state); 913 s5pcsis_clk_put(state);
862 regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies);
863 914
864 media_entity_cleanup(&state->sd.entity); 915 media_entity_cleanup(&state->sd.entity);
865 916