HI Lubomir, On Tue, Nov 20, 2018 at 11:03:19AM +0100, Lubomir Rintel wrote: > The sensor needs the MCLK clock running when it's being probed. On > platforms where the sensor is instantiated from a DT (MMP2) it is going > to happen asynchronously. > > Therefore, the current modus operandi, where the bridge driver fiddles > with the sensor power and clock itself is not going to fly. As the comments > wisely note, this doesn't even belong there. > > Luckily, the ov7670 driver is already able to control its power and > reset lines, we can just drop the MMP platform glue altogether. > > It also requests the clock via the standard clock subsystem. Good -- let's > set up a clock instance so that the sensor can ask us to enable the clock. > Note that this is pretty dumb at the moment: the clock is hardwired to a > particular frequency and parent. It was always the case. > > Signed-off-by: Lubomir Rintel <lkundrak@xxxxx> > > --- > Changes since v1: > - [kbuild/ia64] depend on COMMON_CLK. > - [smatch] fix bad return in mcam_v4l_open() leading to lock not getting > released on error. > > drivers/media/platform/marvell-ccic/Kconfig | 2 + > .../media/platform/marvell-ccic/cafe-driver.c | 9 +- > .../media/platform/marvell-ccic/mcam-core.c | 156 +++++++++++++++--- > .../media/platform/marvell-ccic/mcam-core.h | 3 + > .../media/platform/marvell-ccic/mmp-driver.c | 152 ++--------------- > .../linux/platform_data/media/mmp-camera.h | 2 - > 6 files changed, 161 insertions(+), 163 deletions(-) > > diff --git a/drivers/media/platform/marvell-ccic/Kconfig b/drivers/media/platform/marvell-ccic/Kconfig > index cf12e077203a..3e12eb25740a 100644 > --- a/drivers/media/platform/marvell-ccic/Kconfig > +++ b/drivers/media/platform/marvell-ccic/Kconfig > @@ -1,6 +1,7 @@ > config VIDEO_CAFE_CCIC > tristate "Marvell 88ALP01 (Cafe) CMOS Camera Controller support" > depends on PCI && I2C && VIDEO_V4L2 > + depends on COMMON_CLK > select VIDEO_OV7670 > select VIDEOBUF2_VMALLOC > select VIDEOBUF2_DMA_CONTIG > @@ -14,6 +15,7 @@ config VIDEO_MMP_CAMERA > tristate "Marvell Armada 610 integrated camera controller support" > depends on I2C && VIDEO_V4L2 > depends on ARCH_MMP || COMPILE_TEST > + depends on COMMON_CLK > select VIDEO_OV7670 > select I2C_GPIO > select VIDEOBUF2_VMALLOC > diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c > index 658294d319c0..0e712bb941ba 100644 > --- a/drivers/media/platform/marvell-ccic/cafe-driver.c > +++ b/drivers/media/platform/marvell-ccic/cafe-driver.c > @@ -33,6 +33,7 @@ > #include <linux/wait.h> > #include <linux/delay.h> > #include <linux/io.h> > +#include <linux/clkdev.h> > > #include "mcam-core.h" > > @@ -533,11 +534,10 @@ static int cafe_pci_probe(struct pci_dev *pdev, > goto out_iounmap; > > /* > - * Initialize the controller and leave it powered up. It will > - * stay that way until the sensor driver shows up. > + * Initialize the controller. > */ > cafe_ctlr_init(mcam); > - cafe_ctlr_power_up(mcam); > + > /* > * Set up I2C/SMBUS communications. We have to drop the mutex here > * because the sensor could attach in this call chain, leading to > @@ -555,6 +555,9 @@ static int cafe_pci_probe(struct pci_dev *pdev, > if (ret) > goto out_smbus_shutdown; > > + clkdev_create(mcam->mclk, "xclk", "%d-%04x", > + i2c_adapter_id(cam->i2c_adapter), ov7670_info.addr); > + > if (i2c_new_device(cam->i2c_adapter, &ov7670_info)) { > cam->registered = 1; > return 0; > diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c > index 87812b7287f0..982fbac6472d 100644 > --- a/drivers/media/platform/marvell-ccic/mcam-core.c > +++ b/drivers/media/platform/marvell-ccic/mcam-core.c > @@ -22,6 +22,7 @@ > #include <linux/vmalloc.h> > #include <linux/io.h> > #include <linux/clk.h> > +#include <linux/clk-provider.h> > #include <linux/videodev2.h> > #include <media/v4l2-device.h> > #include <media/v4l2-ioctl.h> > @@ -303,9 +304,6 @@ static void mcam_enable_mipi(struct mcam_camera *mcam) > */ > mcam_reg_write(mcam, REG_CSI2_CTRL0, > CSI2_C0_MIPI_EN | CSI2_C0_ACT_LANE(mcam->lane)); > - mcam_reg_write(mcam, REG_CLKCTRL, > - (mcam->mclk_src << 29) | mcam->mclk_div); > - > mcam->mipi_enabled = true; > } > } > @@ -846,11 +844,6 @@ static void mcam_ctlr_init(struct mcam_camera *cam) > * but it's good to be sure. > */ > mcam_reg_clear_bit(cam, REG_CTRL0, C0_ENABLE); > - /* > - * Clock the sensor appropriately. Controller clock should > - * be 48MHz, sensor "typical" value is half that. > - */ > - mcam_reg_write_mask(cam, REG_CLKCTRL, 2, CLK_DIV_MASK); > spin_unlock_irqrestore(&cam->dev_lock, flags); > } > > @@ -898,14 +891,15 @@ static int mcam_ctlr_power_up(struct mcam_camera *cam) > int ret; > > spin_lock_irqsave(&cam->dev_lock, flags); > - ret = cam->plat_power_up(cam); > - if (ret) { > - spin_unlock_irqrestore(&cam->dev_lock, flags); > - return ret; > + if (cam->plat_power_up) { > + ret = cam->plat_power_up(cam); > + if (ret) { > + spin_unlock_irqrestore(&cam->dev_lock, flags); > + return ret; > + } > } > mcam_reg_clear_bit(cam, REG_CTRL1, C1_PWRDWN); > spin_unlock_irqrestore(&cam->dev_lock, flags); > - msleep(5); /* Just to be sure */ > return 0; > } > > @@ -920,10 +914,101 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam) > * power down routine. > */ > mcam_reg_set_bit(cam, REG_CTRL1, C1_PWRDWN); > - cam->plat_power_down(cam); > + if (cam->plat_power_down) > + cam->plat_power_down(cam); > spin_unlock_irqrestore(&cam->dev_lock, flags); > } > > +/* ---------------------------------------------------------------------- */ > +/* > + * Controller clocks. > + */ > +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]); > + } > +} > + > +/* ---------------------------------------------------------------------- */ > +/* > + * Master sensor clock. > + */ > +static int mclk_prepare(struct clk_hw *hw) > +{ > + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); > + > + clk_prepare(cam->clk[0]); > + return 0; > +} > + > +static void mclk_unprepare(struct clk_hw *hw) > +{ > + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); > + > + clk_unprepare(cam->clk[0]); > +} > + > +static int mclk_enable(struct clk_hw *hw) > +{ > + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); > + int mclk_src; > + int mclk_div; > + > + /* > + * Clock the sensor appropriately. Controller clock should > + * be 48MHz, sensor "typical" value is half that. > + */ > + if (cam->bus_type == V4L2_MBUS_CSI2_DPHY) { > + mclk_src = cam->mclk_src; > + mclk_div = cam->mclk_div; > + } else { > + mclk_src = 3; > + mclk_div = 2; > + } > + > + clk_enable(cam->clk[0]); > + mcam_reg_write(cam, REG_CLKCTRL, (mclk_src << 29) | mclk_div); > + mcam_ctlr_power_up(cam); > + > + return 0; > +} > + > +static void mclk_disable(struct clk_hw *hw) > +{ > + struct mcam_camera *cam = container_of(hw, struct mcam_camera, mclk_hw); > + > + mcam_ctlr_power_down(cam); > + clk_disable(cam->clk[0]); > +} > + > +static unsigned long mclk_recalc_rate(struct clk_hw *hw, > + unsigned long parent_rate) > +{ > + return 48000000; > +} > + > +static const struct clk_ops mclk_ops = { > + .prepare = mclk_prepare, > + .unprepare = mclk_unprepare, > + .enable = mclk_enable, > + .disable = mclk_disable, > + .recalc_rate = mclk_recalc_rate, > +}; > + > /* -------------------------------------------------------------------- */ > /* > * Communications with the sensor. > @@ -948,7 +1033,6 @@ static int mcam_cam_init(struct mcam_camera *cam) > ret = __mcam_cam_reset(cam); > /* Get/set parameters? */ > cam->state = S_IDLE; > - mcam_ctlr_power_down(cam); > return ret; > } > > @@ -1584,9 +1668,10 @@ static int mcam_v4l_open(struct file *filp) > if (ret) > goto out; > if (v4l2_fh_is_singular_file(filp)) { > - ret = mcam_ctlr_power_up(cam); > + ret = sensor_call(cam, core, s_power, 1); > if (ret) > goto out; > + mcam_clk_enable(cam); > __mcam_cam_reset(cam); > mcam_set_config_needed(cam, 1); > } > @@ -1608,7 +1693,8 @@ static int mcam_v4l_release(struct file *filp) > _vb2_fop_release(filp, NULL); > if (last_open) { > mcam_disable_mipi(cam); > - mcam_ctlr_power_down(cam); > + sensor_call(cam, core, s_power, 0); > + mcam_clk_disable(cam); > if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read) > mcam_free_dma_bufs(cam); > } > @@ -1806,6 +1892,7 @@ static const struct v4l2_async_notifier_operations mccic_notify_ops = { > > int mccic_register(struct mcam_camera *cam) > { > + struct clk_init_data mclk_init = { }; > int ret; > > /* > @@ -1838,7 +1925,10 @@ int mccic_register(struct mcam_camera *cam) > mcam_set_config_needed(cam, 1); > cam->pix_format = mcam_def_pix_format; > cam->mbus_code = mcam_def_mbus_code; > - mcam_ctlr_init(cam); > + > + mcam_clk_enable(cam); Am I mis-interpreting the clock bindings, or here you expose a clock source, and sensors are supposed to reference it if they need to. It is then the sensor driver that by calling clk_prepare_enable() on the referenced clock triggers the call of the 'enable' function. It seems to me that here you have exposed a clock provider, but the provider itself enables its clocks... Am I confused? Thanks j > + mcam_ctlr_init(cam); // XXX? > + mcam_clk_disable(cam); > > /* > * Register sensor notifier. > @@ -1857,6 +1947,26 @@ int mccic_register(struct mcam_camera *cam) > goto out; > } > > + /* > + * Register sensor master clock. > + */ > + mclk_init.parent_names = NULL; > + mclk_init.num_parents = 0; > + mclk_init.ops = &mclk_ops; > + mclk_init.name = "mclk"; > + > + of_property_read_string(cam->dev->of_node, "clock-output-names", > + &mclk_init.name); > + > + cam->mclk_hw.init = &mclk_init; > + > + cam->mclk = devm_clk_register(cam->dev, &cam->mclk_hw); > + if (IS_ERR(cam->mclk)) { > + ret = PTR_ERR(cam->mclk); > + dev_err(cam->dev, "can't register clock\n"); > + goto out; > + } > + > /* > * If so requested, try to get our DMA buffers now. > */ > @@ -1884,7 +1994,7 @@ void mccic_shutdown(struct mcam_camera *cam) > */ > if (!list_empty(&cam->vdev.fh_list)) { > cam_warn(cam, "Removing a device with users!\n"); > - mcam_ctlr_power_down(cam); > + sensor_call(cam, core, s_power, 0); > } > if (cam->buffer_mode == B_vmalloc) > mcam_free_dma_bufs(cam); > @@ -1906,7 +2016,8 @@ void mccic_suspend(struct mcam_camera *cam) > enum mcam_state cstate = cam->state; > > mcam_ctlr_stop_dma(cam); > - mcam_ctlr_power_down(cam); > + sensor_call(cam, core, s_power, 0); > + mcam_clk_disable(cam); > cam->state = cstate; > } > mutex_unlock(&cam->s_mutex); > @@ -1919,14 +2030,15 @@ int mccic_resume(struct mcam_camera *cam) > > mutex_lock(&cam->s_mutex); > if (!list_empty(&cam->vdev.fh_list)) { > - ret = mcam_ctlr_power_up(cam); > + mcam_clk_enable(cam); > + ret = sensor_call(cam, core, s_power, 1); > if (ret) { > mutex_unlock(&cam->s_mutex); > return ret; > } > __mcam_cam_reset(cam); > } else { > - mcam_ctlr_power_down(cam); > + sensor_call(cam, core, s_power, 0); > } > mutex_unlock(&cam->s_mutex); > > diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h > index 4a72213aca1a..2e3a7567a76a 100644 > --- a/drivers/media/platform/marvell-ccic/mcam-core.h > +++ b/drivers/media/platform/marvell-ccic/mcam-core.h > @@ -8,6 +8,7 @@ > #define _MCAM_CORE_H > > #include <linux/list.h> > +#include <linux/clk-provider.h> > #include <media/v4l2-common.h> > #include <media/v4l2-ctrls.h> > #include <media/v4l2-dev.h> > @@ -125,6 +126,8 @@ struct mcam_camera { > > /* clock tree support */ > struct clk *clk[NR_MCAM_CLK]; > + struct clk_hw mclk_hw; > + struct clk *mclk; > > /* > * Callbacks from the core to the platform code. > diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c > index efbffb06e25c..7e0783dc9152 100644 > --- a/drivers/media/platform/marvell-ccic/mmp-driver.c > +++ b/drivers/media/platform/marvell-ccic/mmp-driver.c > @@ -22,9 +22,7 @@ > #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> > @@ -38,7 +36,6 @@ MODULE_LICENSE("GPL"); > 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; > @@ -94,94 +91,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 */ > - > -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); > - mcam_clk_enable(mcam); > -/* > - * 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); > - > - 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); > -} > - > /* > * calc the dphy register values > * There are three dphy registers being used. > @@ -327,8 +236,6 @@ 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->calc_dphy = mmpcam_calc_dphy; > mcam->dev = &pdev->dev; > pdata = pdev->dev.platform_data; > @@ -366,33 +273,6 @@ static int mmpcam_probe(struct platform_device *pdev) > if (IS_ERR(mcam->regs)) > return PTR_ERR(mcam->regs); > mcam->regs_size = resource_size(res); > - /* > - * 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); > - /* > - * 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); > > @@ -410,14 +290,21 @@ static int mmpcam_probe(struct platform_device *pdev) > 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 > @@ -426,7 +313,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, > @@ -436,10 +323,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; > } > > @@ -450,7 +337,6 @@ static int mmpcam_remove(struct mmp_camera *cam) > > mmpcam_remove_device(cam); > mccic_shutdown(mcam); > - mmpcam_power_down(mcam); > return 0; > } > > @@ -482,12 +368,6 @@ 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); > } > > diff --git a/include/linux/platform_data/media/mmp-camera.h b/include/linux/platform_data/media/mmp-camera.h > index c573ebc40035..53adaab64f28 100644 > --- a/include/linux/platform_data/media/mmp-camera.h > +++ b/include/linux/platform_data/media/mmp-camera.h > @@ -12,8 +12,6 @@ enum dphy3_algo { > }; > > struct mmp_camera_platform_data { > - int sensor_power_gpio; > - int sensor_reset_gpio; > enum v4l2_mbus_type bus_type; > int mclk_src; /* which clock source the MCLK derives from */ > int mclk_div; /* Clock Divider Value for MCLK */ > -- > 2.19.1 >
Attachment:
signature.asc
Description: PGP signature