diff options
author | Sylwester Nawrocki <s.nawrocki@samsung.com> | 2013-03-21 13:43:17 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2013-03-31 09:58:46 -0400 |
commit | 056f4f3036394892ed591932326c11613b6584c1 (patch) | |
tree | fa84e249a5d7efad0d62cfdc945456d9370fa39d /drivers/media/platform | |
parent | 39bb6df6e35d406ccbe953f1595f650eb6bb88ce (diff) |
[media] s5p-fimc: Add support for PIXELASYNCMx clocks
This patch ads handling of clocks for the CAMBLK subsystem which
is a glue logic for FIMC-IS or LCD controller and FIMC IP.
Signed-off-by: Sylwester Nawrocki <s.nawrocki@samsung.com>
Signed-off-by: Kyungmin Park <kyungmin.park@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/platform')
-rw-r--r-- | drivers/media/platform/s5p-fimc/fimc-mdevice.c | 83 | ||||
-rw-r--r-- | drivers/media/platform/s5p-fimc/fimc-mdevice.h | 10 |
2 files changed, 82 insertions, 11 deletions
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.c b/drivers/media/platform/s5p-fimc/fimc-mdevice.c index 6972f52ba43f..c4a39782d55e 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.c +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.c | |||
@@ -151,26 +151,48 @@ static int fimc_pipeline_s_power(struct fimc_pipeline *p, bool state) | |||
151 | * __fimc_pipeline_open - update the pipeline information, enable power | 151 | * __fimc_pipeline_open - update the pipeline information, enable power |
152 | * of all pipeline subdevs and the sensor clock | 152 | * of all pipeline subdevs and the sensor clock |
153 | * @me: media entity to start graph walk with | 153 | * @me: media entity to start graph walk with |
154 | * @prep: true to acquire sensor (and csis) subdevs | 154 | * @prepare: true to walk the current pipeline and acquire all subdevs |
155 | * | 155 | * |
156 | * Called with the graph mutex held. | 156 | * Called with the graph mutex held. |
157 | */ | 157 | */ |
158 | static int __fimc_pipeline_open(struct fimc_pipeline *p, | 158 | static int __fimc_pipeline_open(struct fimc_pipeline *p, |
159 | struct media_entity *me, bool prep) | 159 | struct media_entity *me, bool prepare) |
160 | { | 160 | { |
161 | struct fimc_md *fmd = entity_to_fimc_mdev(me); | ||
162 | struct v4l2_subdev *sd; | ||
161 | int ret; | 163 | int ret; |
162 | 164 | ||
163 | if (prep) | 165 | if (WARN_ON(p == NULL || me == NULL)) |
166 | return -EINVAL; | ||
167 | |||
168 | if (prepare) | ||
164 | fimc_pipeline_prepare(p, me); | 169 | fimc_pipeline_prepare(p, me); |
165 | 170 | ||
166 | if (p->subdevs[IDX_SENSOR] == NULL) | 171 | sd = p->subdevs[IDX_SENSOR]; |
172 | if (sd == NULL) | ||
167 | return -EINVAL; | 173 | return -EINVAL; |
168 | 174 | ||
169 | ret = fimc_md_set_camclk(p->subdevs[IDX_SENSOR], true); | 175 | /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ |
170 | if (ret) | 176 | if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) { |
171 | return ret; | 177 | ret = clk_prepare_enable(fmd->wbclk[CLK_IDX_WB_B]); |
178 | if (ret < 0) | ||
179 | return ret; | ||
180 | } | ||
181 | ret = fimc_md_set_camclk(sd, true); | ||
182 | if (ret < 0) | ||
183 | goto err_wbclk; | ||
184 | |||
185 | ret = fimc_pipeline_s_power(p, 1); | ||
186 | if (!ret) | ||
187 | return 0; | ||
188 | |||
189 | fimc_md_set_camclk(sd, false); | ||
172 | 190 | ||
173 | return fimc_pipeline_s_power(p, 1); | 191 | err_wbclk: |
192 | if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) | ||
193 | clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); | ||
194 | |||
195 | return ret; | ||
174 | } | 196 | } |
175 | 197 | ||
176 | /** | 198 | /** |
@@ -181,15 +203,24 @@ static int __fimc_pipeline_open(struct fimc_pipeline *p, | |||
181 | */ | 203 | */ |
182 | static int __fimc_pipeline_close(struct fimc_pipeline *p) | 204 | static int __fimc_pipeline_close(struct fimc_pipeline *p) |
183 | { | 205 | { |
206 | struct v4l2_subdev *sd = p ? p->subdevs[IDX_SENSOR] : NULL; | ||
207 | struct fimc_md *fmd; | ||
184 | int ret = 0; | 208 | int ret = 0; |
185 | 209 | ||
186 | if (!p || !p->subdevs[IDX_SENSOR]) | 210 | if (WARN_ON(sd == NULL)) |
187 | return -EINVAL; | 211 | return -EINVAL; |
188 | 212 | ||
189 | if (p->subdevs[IDX_SENSOR]) { | 213 | if (p->subdevs[IDX_SENSOR]) { |
190 | ret = fimc_pipeline_s_power(p, 0); | 214 | ret = fimc_pipeline_s_power(p, 0); |
191 | fimc_md_set_camclk(p->subdevs[IDX_SENSOR], false); | 215 | fimc_md_set_camclk(sd, false); |
192 | } | 216 | } |
217 | |||
218 | fmd = entity_to_fimc_mdev(&sd->entity); | ||
219 | |||
220 | /* Disable PXLASYNC clock if this pipeline includes FIMC-IS */ | ||
221 | if (!IS_ERR(fmd->wbclk[CLK_IDX_WB_B]) && p->subdevs[IDX_IS_ISP]) | ||
222 | clk_disable_unprepare(fmd->wbclk[CLK_IDX_WB_B]); | ||
223 | |||
193 | return ret == -ENXIO ? 0 : ret; | 224 | return ret == -ENXIO ? 0 : ret; |
194 | } | 225 | } |
195 | 226 | ||
@@ -959,7 +990,7 @@ static int fimc_md_create_links(struct fimc_md *fmd) | |||
959 | } | 990 | } |
960 | 991 | ||
961 | /* | 992 | /* |
962 | * The peripheral sensor clock management. | 993 | * The peripheral sensor and CAM_BLK (PIXELASYNCMx) clocks management. |
963 | */ | 994 | */ |
964 | static void fimc_md_put_clocks(struct fimc_md *fmd) | 995 | static void fimc_md_put_clocks(struct fimc_md *fmd) |
965 | { | 996 | { |
@@ -972,6 +1003,14 @@ static void fimc_md_put_clocks(struct fimc_md *fmd) | |||
972 | clk_put(fmd->camclk[i].clock); | 1003 | clk_put(fmd->camclk[i].clock); |
973 | fmd->camclk[i].clock = ERR_PTR(-EINVAL); | 1004 | fmd->camclk[i].clock = ERR_PTR(-EINVAL); |
974 | } | 1005 | } |
1006 | |||
1007 | /* Writeback (PIXELASYNCMx) clocks */ | ||
1008 | for (i = 0; i < FIMC_MAX_WBCLKS; i++) { | ||
1009 | if (IS_ERR(fmd->wbclk[i])) | ||
1010 | continue; | ||
1011 | clk_put(fmd->wbclk[i]); | ||
1012 | fmd->wbclk[i] = ERR_PTR(-EINVAL); | ||
1013 | } | ||
975 | } | 1014 | } |
976 | 1015 | ||
977 | static int fimc_md_get_clocks(struct fimc_md *fmd) | 1016 | static int fimc_md_get_clocks(struct fimc_md *fmd) |
@@ -1008,6 +1047,28 @@ static int fimc_md_get_clocks(struct fimc_md *fmd) | |||
1008 | if (ret) | 1047 | if (ret) |
1009 | fimc_md_put_clocks(fmd); | 1048 | fimc_md_put_clocks(fmd); |
1010 | 1049 | ||
1050 | if (!fmd->use_isp) | ||
1051 | return 0; | ||
1052 | /* | ||
1053 | * For now get only PIXELASYNCM1 clock (Writeback B/ISP), | ||
1054 | * leave PIXELASYNCM0 out for the LCD Writeback driver. | ||
1055 | */ | ||
1056 | fmd->wbclk[CLK_IDX_WB_A] = ERR_PTR(-EINVAL); | ||
1057 | |||
1058 | for (i = CLK_IDX_WB_B; i < FIMC_MAX_WBCLKS; i++) { | ||
1059 | snprintf(clk_name, sizeof(clk_name), "pxl_async%u", i); | ||
1060 | clock = clk_get(dev, clk_name); | ||
1061 | if (IS_ERR(clock)) { | ||
1062 | v4l2_err(&fmd->v4l2_dev, "Failed to get clock: %s\n", | ||
1063 | clk_name); | ||
1064 | ret = PTR_ERR(clock); | ||
1065 | break; | ||
1066 | } | ||
1067 | fmd->wbclk[i] = clock; | ||
1068 | } | ||
1069 | if (ret) | ||
1070 | fimc_md_put_clocks(fmd); | ||
1071 | |||
1011 | return ret; | 1072 | return ret; |
1012 | } | 1073 | } |
1013 | 1074 | ||
diff --git a/drivers/media/platform/s5p-fimc/fimc-mdevice.h b/drivers/media/platform/s5p-fimc/fimc-mdevice.h index 5d6146e76802..46f3b82e0446 100644 --- a/drivers/media/platform/s5p-fimc/fimc-mdevice.h +++ b/drivers/media/platform/s5p-fimc/fimc-mdevice.h | |||
@@ -41,6 +41,13 @@ | |||
41 | #define FIMC_MAX_SENSORS 8 | 41 | #define FIMC_MAX_SENSORS 8 |
42 | #define FIMC_MAX_CAMCLKS 2 | 42 | #define FIMC_MAX_CAMCLKS 2 |
43 | 43 | ||
44 | /* LCD/ISP Writeback clocks (PIXELASYNCMx) */ | ||
45 | enum { | ||
46 | CLK_IDX_WB_A, | ||
47 | CLK_IDX_WB_B, | ||
48 | FIMC_MAX_WBCLKS | ||
49 | }; | ||
50 | |||
44 | struct fimc_csis_info { | 51 | struct fimc_csis_info { |
45 | struct v4l2_subdev *sd; | 52 | struct v4l2_subdev *sd; |
46 | int id; | 53 | int id; |
@@ -73,6 +80,7 @@ struct fimc_sensor_info { | |||
73 | * @num_sensors: actual number of registered sensors | 80 | * @num_sensors: actual number of registered sensors |
74 | * @camclk: external sensor clock information | 81 | * @camclk: external sensor clock information |
75 | * @fimc: array of registered fimc devices | 82 | * @fimc: array of registered fimc devices |
83 | * @use_isp: set to true when FIMC-IS subsystem is used | ||
76 | * @media_dev: top level media device | 84 | * @media_dev: top level media device |
77 | * @v4l2_dev: top level v4l2_device holding up the subdevs | 85 | * @v4l2_dev: top level v4l2_device holding up the subdevs |
78 | * @pdev: platform device this media device is hooked up into | 86 | * @pdev: platform device this media device is hooked up into |
@@ -87,8 +95,10 @@ struct fimc_md { | |||
87 | struct fimc_sensor_info sensor[FIMC_MAX_SENSORS]; | 95 | struct fimc_sensor_info sensor[FIMC_MAX_SENSORS]; |
88 | int num_sensors; | 96 | int num_sensors; |
89 | struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS]; | 97 | struct fimc_camclk_info camclk[FIMC_MAX_CAMCLKS]; |
98 | struct clk *wbclk[FIMC_MAX_WBCLKS]; | ||
90 | struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS]; | 99 | struct fimc_lite *fimc_lite[FIMC_LITE_MAX_DEVS]; |
91 | struct fimc_dev *fimc[FIMC_MAX_DEVS]; | 100 | struct fimc_dev *fimc[FIMC_MAX_DEVS]; |
101 | bool use_isp; | ||
92 | struct media_device media_dev; | 102 | struct media_device media_dev; |
93 | struct v4l2_device v4l2_dev; | 103 | struct v4l2_device v4l2_dev; |
94 | struct platform_device *pdev; | 104 | struct platform_device *pdev; |