aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
authorSylwester Nawrocki <s.nawrocki@samsung.com>2010-12-27 13:34:43 -0500
committerMauro Carvalho Chehab <mchehab@redhat.com>2011-03-21 19:31:39 -0400
commita25be18dfb6e1b172498a9f6c9793d67057000b0 (patch)
treec824969740de62c2ddc9e80bc689d72ff73ae1a9 /drivers/media/video
parentac75934cc644051dc1b33b234448ea4a0990f31f (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.c45
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c59
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h18
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
116static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index) 116static 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
33static char *fimc_clock_name[NUM_FIMC_CLOCKS] = { "sclk_fimc", "fimc" }; 33static char *fimc_clocks[MAX_FIMC_CLOCKS] = {
34 "sclk_fimc", "fimc", "sclk_cam"
35};
34 36
35static struct fimc_fmt fimc_formats[] = { 37static struct fimc_fmt fimc_formats[] = {
36 { 38 {
@@ -1478,7 +1480,7 @@ static void fimc_unregister_m2m_device(struct fimc_dev *fimc)
1478static void fimc_clk_release(struct fimc_dev *fimc) 1480static 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)
1489static int fimc_clk_get(struct fimc_dev *fimc) 1491static 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 */
49enum {
50 CLK_BUS,
51 CLK_GATE,
52 CLK_CAM,
53};
54
49enum fimc_dev_flags { 55enum 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;