diff options
Diffstat (limited to 'drivers/media/platform/s5p-fimc/mipi-csis.c')
-rw-r--r-- | drivers/media/platform/s5p-fimc/mipi-csis.c | 101 |
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 | ||
262 | static void s5pcsis_system_enable(struct csis_state *state, int on) | 274 | static 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) | |||
366 | err: | 385 | err: |
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 | |||
391 | static 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 | ||
372 | static void s5pcsis_start_stream(struct csis_state *state) | 415 | static 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 | ||
752 | e_regput: | 805 | e_clkdis: |
753 | regulator_bulk_free(CSIS_NUM_SUPPLIES, state->supplies); | ||
754 | e_clkput: | ||
755 | clk_disable(state->clock[CSIS_CLK_MUX]); | 806 | clk_disable(state->clock[CSIS_CLK_MUX]); |
807 | e_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 | ||