aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/platform/marvell-ccic/mmp-driver.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/marvell-ccic/mmp-driver.c')
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c238
1 files changed, 55 insertions, 183 deletions
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
index bf4d4a47f1db..10559492e09e 100644
--- a/drivers/media/platform/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -4,13 +4,12 @@
* to work with the Armada 610 as used in the OLPC 1.75 system.
*
* Copyright 2011 Jonathan Corbet <corbet@lwn.net>
+ * Copyright 2018 Lubomir Rintel <lkundrak@v3.sk>
*/
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
-#include <linux/i2c.h>
-#include <linux/platform_data/i2c-gpio.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/slab.h>
@@ -18,10 +17,10 @@
#include <media/v4l2-device.h>
#include <linux/platform_data/media/mmp-camera.h>
#include <linux/device.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
#include <linux/platform_device.h>
-#include <linux/gpio.h>
#include <linux/io.h>
-#include <linux/delay.h>
#include <linux/list.h>
#include <linux/pm.h>
#include <linux/clk.h>
@@ -32,10 +31,9 @@ MODULE_ALIAS("platform:mmp-camera");
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_LICENSE("GPL");
-static char *mcam_clks[] = {"CCICAXICLK", "CCICFUNCLK", "CCICPHYCLK"};
+static char *mcam_clks[] = {"axi", "func", "phy"};
struct mmp_camera {
- void __iomem *power_regs;
struct platform_device *pdev;
struct mcam_camera mcam;
struct list_head devlist;
@@ -91,118 +89,6 @@ static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
return NULL;
}
-
-
-
-/*
- * Power-related registers; this almost certainly belongs
- * somewhere else.
- *
- * ARMADA 610 register manual, sec 7.2.1, p1842.
- */
-#define CPU_SUBSYS_PMU_BASE 0xd4282800
-#define REG_CCIC_DCGCR 0x28 /* CCIC dyn clock gate ctrl reg */
-#define REG_CCIC_CRCR 0x50 /* CCIC clk reset ctrl reg */
-#define REG_CCIC2_CRCR 0xf4 /* CCIC2 clk reset ctrl reg */
-
-static void mcam_clk_enable(struct mcam_camera *mcam)
-{
- unsigned int i;
-
- for (i = 0; i < NR_MCAM_CLK; i++) {
- if (!IS_ERR(mcam->clk[i]))
- clk_prepare_enable(mcam->clk[i]);
- }
-}
-
-static void mcam_clk_disable(struct mcam_camera *mcam)
-{
- int i;
-
- for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
- if (!IS_ERR(mcam->clk[i]))
- clk_disable_unprepare(mcam->clk[i]);
- }
-}
-
-/*
- * Power control.
- */
-static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
-{
- iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
- iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
- mdelay(1);
-}
-
-static int mmpcam_power_up(struct mcam_camera *mcam)
-{
- struct mmp_camera *cam = mcam_to_cam(mcam);
- struct mmp_camera_platform_data *pdata;
-
-/*
- * Turn on power and clocks to the controller.
- */
- mmpcam_power_up_ctlr(cam);
-/*
- * Provide power to the sensor.
- */
- mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002);
- pdata = cam->pdev->dev.platform_data;
- gpio_set_value(pdata->sensor_power_gpio, 1);
- mdelay(5);
- mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000);
- gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */
- mdelay(5);
- gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */
- mdelay(5);
-
- mcam_clk_enable(mcam);
-
- return 0;
-}
-
-static void mmpcam_power_down(struct mcam_camera *mcam)
-{
- struct mmp_camera *cam = mcam_to_cam(mcam);
- struct mmp_camera_platform_data *pdata;
-/*
- * Turn off clocks and set reset lines
- */
- iowrite32(0, cam->power_regs + REG_CCIC_DCGCR);
- iowrite32(0, cam->power_regs + REG_CCIC_CRCR);
-/*
- * Shut down the sensor.
- */
- pdata = cam->pdev->dev.platform_data;
- gpio_set_value(pdata->sensor_power_gpio, 0);
- gpio_set_value(pdata->sensor_reset_gpio, 0);
-
- mcam_clk_disable(mcam);
-}
-
-static void mcam_ctlr_reset(struct mcam_camera *mcam)
-{
- unsigned long val;
- struct mmp_camera *cam = mcam_to_cam(mcam);
-
- if (mcam->ccic_id) {
- /*
- * Using CCIC2
- */
- val = ioread32(cam->power_regs + REG_CCIC2_CRCR);
- iowrite32(val & ~0x2, cam->power_regs + REG_CCIC2_CRCR);
- iowrite32(val | 0x2, cam->power_regs + REG_CCIC2_CRCR);
- } else {
- /*
- * Using CCIC1
- */
- val = ioread32(cam->power_regs + REG_CCIC_CRCR);
- iowrite32(val & ~0x2, cam->power_regs + REG_CCIC_CRCR);
- iowrite32(val | 0x2, cam->power_regs + REG_CCIC_CRCR);
- }
-}
-
/*
* calc the dphy register values
* There are three dphy registers being used.
@@ -334,13 +220,10 @@ static int mmpcam_probe(struct platform_device *pdev)
struct mmp_camera *cam;
struct mcam_camera *mcam;
struct resource *res;
+ struct fwnode_handle *ep;
struct mmp_camera_platform_data *pdata;
int ret;
- pdata = pdev->dev.platform_data;
- if (!pdata)
- return -ENODEV;
-
cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL);
if (cam == NULL)
return -ENOMEM;
@@ -348,25 +231,31 @@ static int mmpcam_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&cam->devlist);
mcam = &cam->mcam;
- mcam->plat_power_up = mmpcam_power_up;
- mcam->plat_power_down = mmpcam_power_down;
- mcam->ctlr_reset = mcam_ctlr_reset;
mcam->calc_dphy = mmpcam_calc_dphy;
mcam->dev = &pdev->dev;
- mcam->use_smbus = 0;
- mcam->ccic_id = pdev->id;
- mcam->mclk_min = pdata->mclk_min;
- mcam->mclk_src = pdata->mclk_src;
- mcam->mclk_div = pdata->mclk_div;
- mcam->bus_type = pdata->bus_type;
- mcam->dphy = pdata->dphy;
+ pdata = pdev->dev.platform_data;
+ if (pdata) {
+ mcam->mclk_src = pdata->mclk_src;
+ mcam->mclk_div = pdata->mclk_div;
+ mcam->bus_type = pdata->bus_type;
+ mcam->dphy = pdata->dphy;
+ mcam->lane = pdata->lane;
+ } else {
+ /*
+ * These are values that used to be hardcoded in mcam-core and
+ * work well on a OLPC XO 1.75 with a parallel bus sensor.
+ * If it turns out other setups make sense, the values should
+ * be obtained from the device tree.
+ */
+ mcam->mclk_src = 3;
+ mcam->mclk_div = 2;
+ }
if (mcam->bus_type == V4L2_MBUS_CSI2_DPHY) {
cam->mipi_clk = devm_clk_get(mcam->dev, "mipi");
if ((IS_ERR(cam->mipi_clk) && mcam->dphy[2] == 0))
return PTR_ERR(cam->mipi_clk);
}
mcam->mipi_enabled = false;
- mcam->lane = pdata->lane;
mcam->chip_id = MCAM_ARMADA610;
mcam->buffer_mode = B_DMA_sg;
strscpy(mcam->bus_info, "platform:mmp-camera", sizeof(mcam->bus_info));
@@ -379,54 +268,39 @@ static int mmpcam_probe(struct platform_device *pdev)
if (IS_ERR(mcam->regs))
return PTR_ERR(mcam->regs);
mcam->regs_size = resource_size(res);
+
+ mcam_init_clk(mcam);
+
/*
- * Power/clock memory is elsewhere; get it too. Perhaps this
- * should really be managed outside of this driver?
- */
- res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- cam->power_regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(cam->power_regs))
- return PTR_ERR(cam->power_regs);
- /*
- * Find the i2c adapter. This assumes, of course, that the
- * i2c bus is already up and functioning.
+ * Create a match of the sensor against its OF node.
*/
- mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
- if (mcam->i2c_adapter == NULL) {
- dev_err(&pdev->dev, "No i2c adapter\n");
+ ep = fwnode_graph_get_next_endpoint(of_fwnode_handle(pdev->dev.of_node),
+ NULL);
+ if (!ep)
return -ENODEV;
- }
- /*
- * Sensor GPIO pins.
- */
- ret = devm_gpio_request(&pdev->dev, pdata->sensor_power_gpio,
- "cam-power");
- if (ret) {
- dev_err(&pdev->dev, "Can't get sensor power gpio %d",
- pdata->sensor_power_gpio);
- return ret;
- }
- gpio_direction_output(pdata->sensor_power_gpio, 0);
- ret = devm_gpio_request(&pdev->dev, pdata->sensor_reset_gpio,
- "cam-reset");
- if (ret) {
- dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
- pdata->sensor_reset_gpio);
- return ret;
- }
- gpio_direction_output(pdata->sensor_reset_gpio, 0);
- mcam_init_clk(mcam);
+ mcam->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+ mcam->asd.match.fwnode = fwnode_graph_get_remote_port_parent(ep);
+
+ fwnode_handle_put(ep);
/*
- * Power the device up and hand it off to the core.
+ * Register the device with the core.
*/
- ret = mmpcam_power_up(mcam);
- if (ret)
- return ret;
ret = mccic_register(mcam);
if (ret)
- goto out_power_down;
+ return ret;
+
+ /*
+ * Add OF clock provider.
+ */
+ ret = of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get,
+ mcam->mclk);
+ if (ret) {
+ dev_err(&pdev->dev, "can't add DT clock provider\n");
+ goto out;
+ }
+
/*
* Finally, set up our IRQ now that the core is ready to
* deal with it.
@@ -434,7 +308,7 @@ static int mmpcam_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
ret = -ENODEV;
- goto out_unregister;
+ goto out;
}
cam->irq = res->start;
ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED,
@@ -444,10 +318,10 @@ static int mmpcam_probe(struct platform_device *pdev)
return 0;
}
-out_unregister:
+out:
+ fwnode_handle_put(mcam->asd.match.fwnode);
mccic_shutdown(mcam);
-out_power_down:
- mmpcam_power_down(mcam);
+
return ret;
}
@@ -458,7 +332,6 @@ static int mmpcam_remove(struct mmp_camera *cam)
mmpcam_remove_device(cam);
mccic_shutdown(mcam);
- mmpcam_power_down(mcam);
return 0;
}
@@ -490,17 +363,15 @@ static int mmpcam_resume(struct platform_device *pdev)
{
struct mmp_camera *cam = mmpcam_find_device(pdev);
- /*
- * Power up unconditionally just in case the core tries to
- * touch a register even if nothing was active before; trust
- * me, it's better this way.
- */
- mmpcam_power_up_ctlr(cam);
return mccic_resume(&cam->mcam);
}
#endif
+static const struct of_device_id mmpcam_of_match[] = {
+ { .compatible = "marvell,mmp2-ccic", },
+ {},
+};
static struct platform_driver mmpcam_driver = {
.probe = mmpcam_probe,
@@ -511,6 +382,7 @@ static struct platform_driver mmpcam_driver = {
#endif
.driver = {
.name = "mmp-camera",
+ .of_match_table = of_match_ptr(mmpcam_of_match),
}
};