aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSakari Ailus <sakari.ailus@iki.fi>2015-03-25 18:57:38 -0400
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2015-04-02 15:47:48 -0400
commitda7f3843d2c797419af6befcc0fdd54f6e13b6f4 (patch)
tree7c18177fdb337c9e8cdfea0cf8702496b026fd87
parentb6eec1c4939962838ff51b10a8feb7a49bccc0d2 (diff)
[media] omap3isp: Add support for the Device Tree
Add the ISP device to omap3 DT include file and add support to the driver to use it. Also obtain information on the external entities and the ISP configuration related to them through the Device Tree in addition to the platform data. Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r--drivers/media/platform/omap3isp/isp.c218
-rw-r--r--drivers/media/platform/omap3isp/isp.h11
-rw-r--r--drivers/media/platform/omap3isp/ispcsiphy.c7
3 files changed, 224 insertions, 12 deletions
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 992e74c3471d..9ef7e035aa6c 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -64,6 +64,7 @@
64 64
65#include <media/v4l2-common.h> 65#include <media/v4l2-common.h>
66#include <media/v4l2-device.h> 66#include <media/v4l2-device.h>
67#include <media/v4l2-of.h>
67 68
68#include "isp.h" 69#include "isp.h"
69#include "ispreg.h" 70#include "ispreg.h"
@@ -1991,6 +1992,13 @@ static int isp_register_entities(struct isp_device *isp)
1991 if (ret < 0) 1992 if (ret < 0)
1992 goto done; 1993 goto done;
1993 1994
1995 /*
1996 * Device Tree --- the external sub-devices will be registered
1997 * later. The same goes for the sub-device node registration.
1998 */
1999 if (isp->dev->of_node)
2000 return 0;
2001
1994 /* Register external entities */ 2002 /* Register external entities */
1995 for (isp_subdev = pdata ? pdata->subdevs : NULL; 2003 for (isp_subdev = pdata ? pdata->subdevs : NULL;
1996 isp_subdev && isp_subdev->board_info; isp_subdev++) { 2004 isp_subdev && isp_subdev->board_info; isp_subdev++) {
@@ -2016,8 +2024,10 @@ static int isp_register_entities(struct isp_device *isp)
2016 ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev); 2024 ret = v4l2_device_register_subdev_nodes(&isp->v4l2_dev);
2017 2025
2018done: 2026done:
2019 if (ret < 0) 2027 if (ret < 0) {
2020 isp_unregister_entities(isp); 2028 isp_unregister_entities(isp);
2029 v4l2_async_notifier_unregister(&isp->notifier);
2030 }
2021 2031
2022 return ret; 2032 return ret;
2023} 2033}
@@ -2232,6 +2242,7 @@ static int isp_remove(struct platform_device *pdev)
2232{ 2242{
2233 struct isp_device *isp = platform_get_drvdata(pdev); 2243 struct isp_device *isp = platform_get_drvdata(pdev);
2234 2244
2245 v4l2_async_notifier_unregister(&isp->notifier);
2235 isp_unregister_entities(isp); 2246 isp_unregister_entities(isp);
2236 isp_cleanup_modules(isp); 2247 isp_cleanup_modules(isp);
2237 isp_xclk_cleanup(isp); 2248 isp_xclk_cleanup(isp);
@@ -2243,6 +2254,156 @@ static int isp_remove(struct platform_device *pdev)
2243 return 0; 2254 return 0;
2244} 2255}
2245 2256
2257enum isp_of_phy {
2258 ISP_OF_PHY_PARALLEL = 0,
2259 ISP_OF_PHY_CSIPHY1,
2260 ISP_OF_PHY_CSIPHY2,
2261};
2262
2263static int isp_of_parse_node(struct device *dev, struct device_node *node,
2264 struct isp_async_subdev *isd)
2265{
2266 struct isp_bus_cfg *buscfg = &isd->bus;
2267 struct v4l2_of_endpoint vep;
2268 unsigned int i;
2269
2270 v4l2_of_parse_endpoint(node, &vep);
2271
2272 dev_dbg(dev, "parsing endpoint %s, interface %u\n", node->full_name,
2273 vep.base.port);
2274
2275 switch (vep.base.port) {
2276 case ISP_OF_PHY_PARALLEL:
2277 buscfg->interface = ISP_INTERFACE_PARALLEL;
2278 buscfg->bus.parallel.data_lane_shift =
2279 vep.bus.parallel.data_shift;
2280 buscfg->bus.parallel.clk_pol =
2281 !!(vep.bus.parallel.flags
2282 & V4L2_MBUS_PCLK_SAMPLE_FALLING);
2283 buscfg->bus.parallel.hs_pol =
2284 !!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
2285 buscfg->bus.parallel.vs_pol =
2286 !!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
2287 buscfg->bus.parallel.fld_pol =
2288 !!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
2289 buscfg->bus.parallel.data_pol =
2290 !!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
2291 break;
2292
2293 case ISP_OF_PHY_CSIPHY1:
2294 case ISP_OF_PHY_CSIPHY2:
2295 /* FIXME: always assume CSI-2 for now. */
2296 switch (vep.base.port) {
2297 case ISP_OF_PHY_CSIPHY1:
2298 buscfg->interface = ISP_INTERFACE_CSI2C_PHY1;
2299 break;
2300 case ISP_OF_PHY_CSIPHY2:
2301 buscfg->interface = ISP_INTERFACE_CSI2A_PHY2;
2302 break;
2303 }
2304 buscfg->bus.csi2.lanecfg.clk.pos = vep.bus.mipi_csi2.clock_lane;
2305 buscfg->bus.csi2.lanecfg.clk.pol =
2306 vep.bus.mipi_csi2.lane_polarities[0];
2307 dev_dbg(dev, "clock lane polarity %u, pos %u\n",
2308 buscfg->bus.csi2.lanecfg.clk.pol,
2309 buscfg->bus.csi2.lanecfg.clk.pos);
2310
2311 for (i = 0; i < ISP_CSIPHY2_NUM_DATA_LANES; i++) {
2312 buscfg->bus.csi2.lanecfg.data[i].pos =
2313 vep.bus.mipi_csi2.data_lanes[i];
2314 buscfg->bus.csi2.lanecfg.data[i].pol =
2315 vep.bus.mipi_csi2.lane_polarities[i + 1];
2316 dev_dbg(dev, "data lane %u polarity %u, pos %u\n", i,
2317 buscfg->bus.csi2.lanecfg.data[i].pol,
2318 buscfg->bus.csi2.lanecfg.data[i].pos);
2319 }
2320
2321 /*
2322 * FIXME: now we assume the CRC is always there.
2323 * Implement a way to obtain this information from the
2324 * sensor. Frame descriptors, perhaps?
2325 */
2326 buscfg->bus.csi2.crc = 1;
2327 break;
2328
2329 default:
2330 dev_warn(dev, "%s: invalid interface %u\n", node->full_name,
2331 vep.base.port);
2332 break;
2333 }
2334
2335 return 0;
2336}
2337
2338static int isp_of_parse_nodes(struct device *dev,
2339 struct v4l2_async_notifier *notifier)
2340{
2341 struct device_node *node = NULL;
2342
2343 notifier->subdevs = devm_kcalloc(
2344 dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL);
2345 if (!notifier->subdevs)
2346 return -ENOMEM;
2347
2348 while (notifier->num_subdevs < ISP_MAX_SUBDEVS &&
2349 (node = of_graph_get_next_endpoint(dev->of_node, node))) {
2350 struct isp_async_subdev *isd;
2351
2352 isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL);
2353 if (!isd) {
2354 of_node_put(node);
2355 return -ENOMEM;
2356 }
2357
2358 notifier->subdevs[notifier->num_subdevs] = &isd->asd;
2359
2360 if (isp_of_parse_node(dev, node, isd)) {
2361 of_node_put(node);
2362 return -EINVAL;
2363 }
2364
2365 isd->asd.match.of.node = of_graph_get_remote_port_parent(node);
2366 of_node_put(node);
2367 if (!isd->asd.match.of.node) {
2368 dev_warn(dev, "bad remote port parent\n");
2369 return -EINVAL;
2370 }
2371
2372 isd->asd.match_type = V4L2_ASYNC_MATCH_OF;
2373 notifier->num_subdevs++;
2374 }
2375
2376 return notifier->num_subdevs;
2377}
2378
2379static int isp_subdev_notifier_bound(struct v4l2_async_notifier *async,