diff options
author | Sylwester Nawrocki <s.nawrocki@samsung.com> | 2010-12-27 13:34:43 -0500 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-03-21 19:31:39 -0400 |
commit | a25be18dfb6e1b172498a9f6c9793d67057000b0 (patch) | |
tree | c824969740de62c2ddc9e80bc689d72ff73ae1a9 /drivers/media/video | |
parent | ac75934cc644051dc1b33b234448ea4a0990f31f (diff) |
[media] s5p-fimc: Add control of the external sensor clock
Manage the camera sensor clock in the host driver rather than
leaving this task for sensor drivers. The clock frequency
must be passed in the sensor's and host driver's platform data.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/video')
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-capture.c | 45 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.c | 59 | ||||
-rw-r--r-- | drivers/media/video/s5p-fimc/fimc-core.h | 18 |
3 files changed, 80 insertions, 42 deletions
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c index c6689a24c85b..03ddf5d6164f 100644 --- a/drivers/media/video/s5p-fimc/fimc-capture.c +++ b/drivers/media/video/s5p-fimc/fimc-capture.c | |||
@@ -113,26 +113,43 @@ static int fimc_subdev_attach(struct fimc_dev *fimc, int index) | |||
113 | return -ENODEV; | 113 | return -ENODEV; |
114 | } | 114 | } |
115 | 115 | ||
116 | static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index) | 116 | static int fimc_isp_subdev_init(struct fimc_dev *fimc, unsigned int index) |
117 | { | 117 | { |
118 | struct s5p_fimc_isp_info *isp_info; | 118 | struct s5p_fimc_isp_info *isp_info; |
119 | int ret; | 119 | int ret; |
120 | 120 | ||
121 | if (index >= FIMC_MAX_CAMIF_CLIENTS) | ||
122 | return -EINVAL; | ||
123 | |||
124 | isp_info = fimc->pdata->isp_info[index]; | ||
125 | if (!isp_info) | ||
126 | return -EINVAL; | ||
127 | |||
128 | if (isp_info->clk_frequency) | ||
129 | clk_set_rate(fimc->clock[CLK_CAM], isp_info->clk_frequency); | ||
130 | |||
131 | ret = clk_enable(fimc->clock[CLK_CAM]); | ||
132 | if (ret) | ||
133 | return ret; | ||
134 | |||
121 | ret = fimc_subdev_attach(fimc, index); | 135 | ret = fimc_subdev_attach(fimc, index); |
122 | if (ret) | 136 | if (ret) |
123 | return ret; | 137 | return ret; |
124 | 138 | ||
125 | isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index]; | ||
126 | ret = fimc_hw_set_camera_polarity(fimc, isp_info); | 139 | ret = fimc_hw_set_camera_polarity(fimc, isp_info); |
127 | if (!ret) { | 140 | if (ret) |
128 | ret = v4l2_subdev_call(fimc->vid_cap.sd, core, | 141 | return ret; |
129 | s_power, 1); | 142 | |
130 | if (!ret) | 143 | ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 1); |
131 | return ret; | 144 | if (!ret) |
132 | } | 145 | return ret; |
133 | 146 | ||
147 | /* enabling power failed so unregister subdev */ | ||
134 | fimc_subdev_unregister(fimc); | 148 | fimc_subdev_unregister(fimc); |
135 | err("ISP initialization failed: %d", ret); | 149 | |
150 | v4l2_err(&fimc->vid_cap.v4l2_dev, "ISP initialization failed: %d\n", | ||
151 | ret); | ||
152 | |||
136 | return ret; | 153 | return ret; |
137 | } | 154 | } |
138 | 155 | ||
@@ -190,10 +207,7 @@ static int fimc_stop_capture(struct fimc_dev *fimc) | |||
190 | test_bit(ST_CAPT_SHUT, &fimc->state), | 207 | test_bit(ST_CAPT_SHUT, &fimc->state), |
191 | FIMC_SHUTDOWN_TIMEOUT); | 208 | FIMC_SHUTDOWN_TIMEOUT); |
192 | 209 | ||
193 | ret = v4l2_subdev_call(cap->sd, video, s_stream, 0); | 210 | v4l2_subdev_call(cap->sd, video, s_stream, 0); |
194 | |||
195 | if (ret && ret != -ENOIOCTLCMD) | ||
196 | v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n"); | ||
197 | 211 | ||
198 | spin_lock_irqsave(&fimc->slock, flags); | 212 | spin_lock_irqsave(&fimc->slock, flags); |
199 | fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | | 213 | fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND | |
@@ -408,7 +422,7 @@ static int fimc_capture_open(struct file *file) | |||
408 | return -EBUSY; | 422 | return -EBUSY; |
409 | 423 | ||
410 | if (++fimc->vid_cap.refcnt == 1) { | 424 | if (++fimc->vid_cap.refcnt == 1) { |
411 | ret = fimc_isp_subdev_init(fimc, -1); | 425 | ret = fimc_isp_subdev_init(fimc, 0); |
412 | if (ret) { | 426 | if (ret) { |
413 | fimc->vid_cap.refcnt--; | 427 | fimc->vid_cap.refcnt--; |
414 | return -EIO; | 428 | return -EIO; |
@@ -433,6 +447,7 @@ static int fimc_capture_close(struct file *file) | |||
433 | v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n"); | 447 | v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n"); |
434 | 448 | ||
435 | v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); | 449 | v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); |
450 | clk_disable(fimc->clock[CLK_CAM]); | ||
436 | fimc_subdev_unregister(fimc); | 451 | fimc_subdev_unregister(fimc); |
437 | } | 452 | } |
438 | 453 | ||
@@ -604,6 +619,8 @@ static int fimc_cap_s_input(struct file *file, void *priv, | |||
604 | int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); | 619 | int ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0); |
605 | if (ret) | 620 | if (ret) |
606 | err("s_power failed: %d", ret); | 621 | err("s_power failed: %d", ret); |
622 | |||
623 | clk_disable(fimc->clock[CLK_CAM]); | ||
607 | } | 624 | } |
608 | 625 | ||
609 | /* Release the attached sensor subdevice. */ | 626 | /* Release the attached sensor subdevice. */ |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c index b8d59f44a088..db249e6c355d 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.c +++ b/drivers/media/video/s5p-fimc/fimc-core.c | |||
@@ -30,7 +30,9 @@ | |||
30 | 30 | ||
31 | #include "fimc-core.h" | 31 | #include "fimc-core.h" |
32 | 32 | ||
33 | static char *fimc_clock_name[NUM_FIMC_CLOCKS] = { "sclk_fimc", "fimc" }; | 33 | static char *fimc_clocks[MAX_FIMC_CLOCKS] = { |
34 | "sclk_fimc", "fimc", "sclk_cam" | ||
35 | }; | ||
34 | 36 | ||
35 | static struct fimc_fmt fimc_formats[] = { | 37 | static struct fimc_fmt fimc_formats[] = { |
36 | { | 38 | { |
@@ -1478,7 +1480,7 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc) | |||
1478 | static void fimc_clk_release(struct fimc_dev *fimc) | 1480 | static void fimc_clk_release(struct fimc_dev *fimc) |
1479 | { | 1481 | { |
1480 | int i; | 1482 | int i; |
1481 | for (i = 0; i < NUM_FIMC_CLOCKS; i++) { | 1483 | for (i = 0; i < fimc->num_clocks; i++) { |
1482 | if (fimc->clock[i]) { | 1484 | if (fimc->clock[i]) { |
1483 | clk_disable(fimc->clock[i]); | 1485 | clk_disable(fimc->clock[i]); |
1484 | clk_put(fimc->clock[i]); | 1486 | clk_put(fimc->clock[i]); |
@@ -1489,15 +1491,16 @@ static void fimc_clk_release(struct fimc_dev *fimc) | |||
1489 | static int fimc_clk_get(struct fimc_dev *fimc) | 1491 | static int fimc_clk_get(struct fimc_dev *fimc) |
1490 | { | 1492 | { |
1491 | int i; | 1493 | int i; |
1492 | for (i = 0; i < NUM_FIMC_CLOCKS; i++) { | 1494 | for (i = 0; i < fimc->num_clocks; i++) { |
1493 | fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clock_name[i]); | 1495 | fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clocks[i]); |
1494 | if (IS_ERR(fimc->clock[i])) { | 1496 | |
1495 | dev_err(&fimc->pdev->dev, | 1497 | if (!IS_ERR_OR_NULL(fimc->clock[i])) { |
1496 | "failed to get fimc clock: %s\n", | 1498 | clk_enable(fimc->clock[i]); |
1497 | fimc_clock_name[i]); | 1499 | continue; |
1498 | return -ENXIO; | ||
1499 | } | 1500 | } |
1500 | clk_enable(fimc->clock[i]); | 1501 | dev_err(&fimc->pdev->dev, "failed to get fimc clock: %s\n", |
1502 | fimc_clocks[i]); | ||
1503 | return -ENXIO; | ||
1501 | } | 1504 | } |
1502 | return 0; | 1505 | return 0; |
1503 | } | 1506 | } |
@@ -1508,6 +1511,7 @@ static int fimc_probe(struct platform_device *pdev) | |||
1508 | struct resource *res; | 1511 | struct resource *res; |
1509 | struct samsung_fimc_driverdata *drv_data; | 1512 | struct samsung_fimc_driverdata *drv_data; |
1510 | int ret = 0; | 1513 | int ret = 0; |
1514 | int cap_input_index = -1; | ||
1511 | 1515 | ||
1512 | dev_dbg(&pdev->dev, "%s():\n", __func__); | 1516 | dev_dbg(&pdev->dev, "%s():\n", __func__); |
1513 | 1517 | ||
@@ -1557,10 +1561,26 @@ static int fimc_probe(struct platform_device *pdev) | |||
1557 | goto err_req_region; | 1561 | goto err_req_region; |
1558 | } | 1562 | } |
1559 | 1563 | ||
1564 | fimc->num_clocks = MAX_FIMC_CLOCKS - 1; | ||
1565 | /* | ||
1566 | * Check if vide capture node needs to be registered for this device | ||
1567 | * instance. | ||
1568 | */ | ||
1569 | if (fimc->pdata) { | ||
1570 | int i; | ||
1571 | for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) | ||
1572 | if (fimc->pdata->isp_info[i]) | ||
1573 | break; | ||
1574 | if (i < FIMC_MAX_CAMIF_CLIENTS) { | ||
1575 | cap_input_index = i; | ||
1576 | fimc->num_clocks++; | ||
1577 | } | ||
1578 | } | ||
1579 | |||
1560 | ret = fimc_clk_get(fimc); | 1580 | ret = fimc_clk_get(fimc); |
1561 | if (ret) | 1581 | if (ret) |
1562 | goto err_regs_unmap; | 1582 | goto err_regs_unmap; |
1563 | clk_set_rate(fimc->clock[0], drv_data->lclk_frequency); | 1583 | clk_set_rate(fimc->clock[CLK_BUS], drv_data->lclk_frequency); |
1564 | 1584 | ||
1565 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); | 1585 | res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
1566 | if (!res) { | 1586 | if (!res) { |
@@ -1590,19 +1610,12 @@ static int fimc_probe(struct platform_device *pdev) | |||
1590 | goto err_irq; | 1610 | goto err_irq; |
1591 | 1611 | ||
1592 | /* At least one camera sensor is required to register capture node */ | 1612 | /* At least one camera sensor is required to register capture node */ |
1593 | if (fimc->pdata) { | 1613 | if (cap_input_index >= 0) { |
1594 | int i; | 1614 | ret = fimc_register_capture_device(fimc); |
1595 | for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) | 1615 | if (ret) |
1596 | if (fimc->pdata->isp_info[i]) | 1616 | goto err_m2m; |
1597 | break; | 1617 | clk_disable(fimc->clock[CLK_CAM]); |
1598 | |||
1599 | if (i < FIMC_MAX_CAMIF_CLIENTS) { | ||
1600 | ret = fimc_register_capture_device(fimc); | ||
1601 | if (ret) | ||
1602 | goto err_m2m; | ||
1603 | } | ||
1604 | } | 1618 | } |
1605 | |||
1606 | /* | 1619 | /* |
1607 | * Exclude the additional output DMA address registers by masking | 1620 | * Exclude the additional output DMA address registers by masking |
1608 | * them out on HW revisions that provide extended capabilites. | 1621 | * them out on HW revisions that provide extended capabilites. |
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h index b23d492796e9..1c6aa6924550 100644 --- a/drivers/media/video/s5p-fimc/fimc-core.h +++ b/drivers/media/video/s5p-fimc/fimc-core.h | |||
@@ -37,7 +37,7 @@ | |||
37 | 37 | ||
38 | /* Time to wait for next frame VSYNC interrupt while stopping operation. */ | 38 | /* Time to wait for next frame VSYNC interrupt while stopping operation. */ |
39 | #define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) | 39 | #define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000) |
40 | #define NUM_FIMC_CLOCKS 2 | 40 | #define MAX_FIMC_CLOCKS 3 |
41 | #define MODULE_NAME "s5p-fimc" | 41 | #define MODULE_NAME "s5p-fimc" |
42 | #define FIMC_MAX_DEVS 4 | 42 | #define FIMC_MAX_DEVS 4 |
43 | #define FIMC_MAX_OUT_BUFS 4 | 43 | #define FIMC_MAX_OUT_BUFS 4 |
@@ -45,7 +45,13 @@ | |||
45 | #define SCALER_MAX_VRATIO 64 | 45 | #define SCALER_MAX_VRATIO 64 |
46 | #define DMA_MIN_SIZE 8 | 46 | #define DMA_MIN_SIZE 8 |
47 | 47 | ||
48 | /* FIMC device state flags */ | 48 | /* indices to the clocks array */ |
49 | enum { | ||
50 | CLK_BUS, | ||
51 | CLK_GATE, | ||
52 | CLK_CAM, | ||
53 | }; | ||
54 | |||
49 | enum fimc_dev_flags { | 55 | enum fimc_dev_flags { |
50 | /* for m2m node */ | 56 | /* for m2m node */ |
51 | ST_IDLE, | 57 | ST_IDLE, |
@@ -407,7 +413,8 @@ struct fimc_ctx; | |||
407 | * @lock: the mutex protecting this data structure | 413 | * @lock: the mutex protecting this data structure |
408 | * @pdev: pointer to the FIMC platform device | 414 | * @pdev: pointer to the FIMC platform device |
409 | * @pdata: pointer to the device platform data | 415 | * @pdata: pointer to the device platform data |
410 | * @id: FIMC device index (0..2) | 416 | * @id: FIMC device index (0..FIMC_MAX_DEVS) |
417 | * @num_clocks: the number of clocks managed by this device instance | ||
411 | * @clock[]: the clocks required for FIMC operation | 418 | * @clock[]: the clocks required for FIMC operation |
412 | * @regs: the mapped hardware registers | 419 | * @regs: the mapped hardware registers |
413 | * @regs_res: the resource claimed for IO registers | 420 | * @regs_res: the resource claimed for IO registers |
@@ -423,8 +430,9 @@ struct fimc_dev { | |||
423 | struct platform_device *pdev; | 430 | struct platform_device *pdev; |
424 | struct s5p_platform_fimc *pdata; | 431 | struct s5p_platform_fimc *pdata; |
425 | struct samsung_fimc_variant *variant; | 432 | struct samsung_fimc_variant *variant; |
426 | int id; | 433 | u16 id; |
427 | struct clk *clock[NUM_FIMC_CLOCKS]; | 434 | u16 num_clocks; |
435 | struct clk *clock[MAX_FIMC_CLOCKS]; | ||
428 | void __iomem *regs; | 436 | void __iomem *regs; |
429 | struct resource *regs_res; | 437 | struct resource *regs_res; |
430 | int irq; | 438 | int irq; |