linux/drivers/media/platform/marvell-ccic/mmp-driver.c
<<
>>
Prefs
   1/*
   2 * Support for the camera device found on Marvell MMP processors; known
   3 * to work with the Armada 610 as used in the OLPC 1.75 system.
   4 *
   5 * Copyright 2011 Jonathan Corbet <corbet@lwn.net>
   6 *
   7 * This file may be distributed under the terms of the GNU General
   8 * Public License, version 2.
   9 */
  10
  11#include <linux/init.h>
  12#include <linux/kernel.h>
  13#include <linux/module.h>
  14#include <linux/i2c.h>
  15#include <linux/i2c-gpio.h>
  16#include <linux/interrupt.h>
  17#include <linux/spinlock.h>
  18#include <linux/slab.h>
  19#include <linux/videodev2.h>
  20#include <media/v4l2-device.h>
  21#include <media/mmp-camera.h>
  22#include <linux/device.h>
  23#include <linux/platform_device.h>
  24#include <linux/gpio.h>
  25#include <linux/io.h>
  26#include <linux/delay.h>
  27#include <linux/list.h>
  28#include <linux/pm.h>
  29
  30#include "mcam-core.h"
  31
  32MODULE_ALIAS("platform:mmp-camera");
  33MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
  34MODULE_LICENSE("GPL");
  35
  36struct mmp_camera {
  37        void *power_regs;
  38        struct platform_device *pdev;
  39        struct mcam_camera mcam;
  40        struct list_head devlist;
  41        int irq;
  42};
  43
  44static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam)
  45{
  46        return container_of(mcam, struct mmp_camera, mcam);
  47}
  48
  49/*
  50 * A silly little infrastructure so we can keep track of our devices.
  51 * Chances are that we will never have more than one of them, but
  52 * the Armada 610 *does* have two controllers...
  53 */
  54
  55static LIST_HEAD(mmpcam_devices);
  56static struct mutex mmpcam_devices_lock;
  57
  58static void mmpcam_add_device(struct mmp_camera *cam)
  59{
  60        mutex_lock(&mmpcam_devices_lock);
  61        list_add(&cam->devlist, &mmpcam_devices);
  62        mutex_unlock(&mmpcam_devices_lock);
  63}
  64
  65static void mmpcam_remove_device(struct mmp_camera *cam)
  66{
  67        mutex_lock(&mmpcam_devices_lock);
  68        list_del(&cam->devlist);
  69        mutex_unlock(&mmpcam_devices_lock);
  70}
  71
  72/*
  73 * Platform dev remove passes us a platform_device, and there's
  74 * no handy unused drvdata to stash a backpointer in.  So just
  75 * dig it out of our list.
  76 */
  77static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
  78{
  79        struct mmp_camera *cam;
  80
  81        mutex_lock(&mmpcam_devices_lock);
  82        list_for_each_entry(cam, &mmpcam_devices, devlist) {
  83                if (cam->pdev == pdev) {
  84                        mutex_unlock(&mmpcam_devices_lock);
  85                        return cam;
  86                }
  87        }
  88        mutex_unlock(&mmpcam_devices_lock);
  89        return NULL;
  90}
  91
  92
  93
  94
  95/*
  96 * Power-related registers; this almost certainly belongs
  97 * somewhere else.
  98 *
  99 * ARMADA 610 register manual, sec 7.2.1, p1842.
 100 */
 101#define CPU_SUBSYS_PMU_BASE     0xd4282800
 102#define REG_CCIC_DCGCR          0x28    /* CCIC dyn clock gate ctrl reg */
 103#define REG_CCIC_CRCR           0x50    /* CCIC clk reset ctrl reg      */
 104
 105/*
 106 * Power control.
 107 */
 108static void mmpcam_power_up_ctlr(struct mmp_camera *cam)
 109{
 110        iowrite32(0x3f, cam->power_regs + REG_CCIC_DCGCR);
 111        iowrite32(0x3805b, cam->power_regs + REG_CCIC_CRCR);
 112        mdelay(1);
 113}
 114
 115static void mmpcam_power_up(struct mcam_camera *mcam)
 116{
 117        struct mmp_camera *cam = mcam_to_cam(mcam);
 118        struct mmp_camera_platform_data *pdata;
 119/*
 120 * Turn on power and clocks to the controller.
 121 */
 122        mmpcam_power_up_ctlr(cam);
 123/*
 124 * Provide power to the sensor.
 125 */
 126        mcam_reg_write(mcam, REG_CLKCTRL, 0x60000002);
 127        pdata = cam->pdev->dev.platform_data;
 128        gpio_set_value(pdata->sensor_power_gpio, 1);
 129        mdelay(5);
 130        mcam_reg_clear_bit(mcam, REG_CTRL1, 0x10000000);
 131        gpio_set_value(pdata->sensor_reset_gpio, 0); /* reset is active low */
 132        mdelay(5);
 133        gpio_set_value(pdata->sensor_reset_gpio, 1); /* reset is active low */
 134        mdelay(5);
 135}
 136
 137static void mmpcam_power_down(struct mcam_camera *mcam)
 138{
 139        struct mmp_camera *cam = mcam_to_cam(mcam);
 140        struct mmp_camera_platform_data *pdata;
 141/*
 142 * Turn off clocks and set reset lines
 143 */
 144        iowrite32(0, cam->power_regs + REG_CCIC_DCGCR);
 145        iowrite32(0, cam->power_regs + REG_CCIC_CRCR);
 146/*
 147 * Shut down the sensor.
 148 */
 149        pdata = cam->pdev->dev.platform_data;
 150        gpio_set_value(pdata->sensor_power_gpio, 0);
 151        gpio_set_value(pdata->sensor_reset_gpio, 0);
 152}
 153
 154
 155static irqreturn_t mmpcam_irq(int irq, void *data)
 156{
 157        struct mcam_camera *mcam = data;
 158        unsigned int irqs, handled;
 159
 160        spin_lock(&mcam->dev_lock);
 161        irqs = mcam_reg_read(mcam, REG_IRQSTAT);
 162        handled = mccic_irq(mcam, irqs);
 163        spin_unlock(&mcam->dev_lock);
 164        return IRQ_RETVAL(handled);
 165}
 166
 167
 168static int mmpcam_probe(struct platform_device *pdev)
 169{
 170        struct mmp_camera *cam;
 171        struct mcam_camera *mcam;
 172        struct resource *res;
 173        struct mmp_camera_platform_data *pdata;
 174        int ret;
 175
 176        cam = kzalloc(sizeof(*cam), GFP_KERNEL);
 177        if (cam == NULL)
 178                return -ENOMEM;
 179        cam->pdev = pdev;
 180        INIT_LIST_HEAD(&cam->devlist);
 181
 182        mcam = &cam->mcam;
 183        mcam->plat_power_up = mmpcam_power_up;
 184        mcam->plat_power_down = mmpcam_power_down;
 185        mcam->dev = &pdev->dev;
 186        mcam->use_smbus = 0;
 187        mcam->chip_id = MCAM_ARMADA610;
 188        mcam->buffer_mode = B_DMA_sg;
 189        spin_lock_init(&mcam->dev_lock);
 190        /*
 191         * Get our I/O memory.
 192         */
 193        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 194        if (res == NULL) {
 195                dev_err(&pdev->dev, "no iomem resource!\n");
 196                ret = -ENODEV;
 197                goto out_free;
 198        }
 199        mcam->regs = ioremap(res->start, resource_size(res));
 200        if (mcam->regs == NULL) {
 201                dev_err(&pdev->dev, "MMIO ioremap fail\n");
 202                ret = -ENODEV;
 203                goto out_free;
 204        }
 205        mcam->regs_size = resource_size(res);
 206        /*
 207         * Power/clock memory is elsewhere; get it too.  Perhaps this
 208         * should really be managed outside of this driver?
 209         */
 210        res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
 211        if (res == NULL) {
 212                dev_err(&pdev->dev, "no power resource!\n");
 213                ret = -ENODEV;
 214                goto out_unmap1;
 215        }
 216        cam->power_regs = ioremap(res->start, resource_size(res));
 217        if (cam->power_regs == NULL) {
 218                dev_err(&pdev->dev, "power MMIO ioremap fail\n");
 219                ret = -ENODEV;
 220                goto out_unmap1;
 221        }
 222        /*
 223         * Find the i2c adapter.  This assumes, of course, that the
 224         * i2c bus is already up and functioning.
 225         */
 226        pdata = pdev->dev.platform_data;
 227        mcam->i2c_adapter = platform_get_drvdata(pdata->i2c_device);
 228        if (mcam->i2c_adapter == NULL) {
 229                ret = -ENODEV;
 230                dev_err(&pdev->dev, "No i2c adapter\n");
 231                goto out_unmap2;
 232        }
 233        /*
 234         * Sensor GPIO pins.
 235         */
 236        ret = gpio_request(pdata->sensor_power_gpio, "cam-power");
 237        if (ret) {
 238                dev_err(&pdev->dev, "Can't get sensor power gpio %d",
 239                                pdata->sensor_power_gpio);
 240                goto out_unmap2;
 241        }
 242        gpio_direction_output(pdata->sensor_power_gpio, 0);
 243        ret = gpio_request(pdata->sensor_reset_gpio, "cam-reset");
 244        if (ret) {
 245                dev_err(&pdev->dev, "Can't get sensor reset gpio %d",
 246                                pdata->sensor_reset_gpio);
 247                goto out_gpio;
 248        }
 249        gpio_direction_output(pdata->sensor_reset_gpio, 0);
 250        /*
 251         * Power the device up and hand it off to the core.
 252         */
 253        mmpcam_power_up(mcam);
 254        ret = mccic_register(mcam);
 255        if (ret)
 256                goto out_gpio2;
 257        /*
 258         * Finally, set up our IRQ now that the core is ready to
 259         * deal with it.
 260         */
 261        res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
 262        if (res == NULL) {
 263                ret = -ENODEV;
 264                goto out_unregister;
 265        }
 266        cam->irq = res->start;
 267        ret = request_irq(cam->irq, mmpcam_irq, IRQF_SHARED,
 268                        "mmp-camera", mcam);
 269        if (ret == 0) {
 270                mmpcam_add_device(cam);
 271                return 0;
 272        }
 273
 274out_unregister:
 275        mccic_shutdown(mcam);
 276out_gpio2:
 277        mmpcam_power_down(mcam);
 278        gpio_free(pdata->sensor_reset_gpio);
 279out_gpio:
 280        gpio_free(pdata->sensor_power_gpio);
 281out_unmap2:
 282        iounmap(cam->power_regs);
 283out_unmap1:
 284        iounmap(mcam->regs);
 285out_free:
 286        kfree(cam);
 287        return ret;
 288}
 289
 290
 291static int mmpcam_remove(struct mmp_camera *cam)
 292{
 293        struct mcam_camera *mcam = &cam->mcam;
 294        struct mmp_camera_platform_data *pdata;
 295
 296        mmpcam_remove_device(cam);
 297        free_irq(cam->irq, mcam);
 298        mccic_shutdown(mcam);
 299        mmpcam_power_down(mcam);
 300        pdata = cam->pdev->dev.platform_data;
 301        gpio_free(pdata->sensor_reset_gpio);
 302        gpio_free(pdata->sensor_power_gpio);
 303        iounmap(cam->power_regs);
 304        iounmap(mcam->regs);
 305        kfree(cam);
 306        return 0;
 307}
 308
 309static int mmpcam_platform_remove(struct platform_device *pdev)
 310{
 311        struct mmp_camera *cam = mmpcam_find_device(pdev);
 312
 313        if (cam == NULL)
 314                return -ENODEV;
 315        return mmpcam_remove(cam);
 316}
 317
 318/*
 319 * Suspend/resume support.
 320 */
 321#ifdef CONFIG_PM
 322
 323static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state)
 324{
 325        struct mmp_camera *cam = mmpcam_find_device(pdev);
 326
 327        if (state.event != PM_EVENT_SUSPEND)
 328                return 0;
 329        mccic_suspend(&cam->mcam);
 330        return 0;
 331}
 332
 333static int mmpcam_resume(struct platform_device *pdev)
 334{
 335        struct mmp_camera *cam = mmpcam_find_device(pdev);
 336
 337        /*
 338         * Power up unconditionally just in case the core tries to
 339         * touch a register even if nothing was active before; trust
 340         * me, it's better this way.
 341         */
 342        mmpcam_power_up_ctlr(cam);
 343        return mccic_resume(&cam->mcam);
 344}
 345
 346#endif
 347
 348
 349static struct platform_driver mmpcam_driver = {
 350        .probe          = mmpcam_probe,
 351        .remove         = mmpcam_platform_remove,
 352#ifdef CONFIG_PM
 353        .suspend        = mmpcam_suspend,
 354        .resume         = mmpcam_resume,
 355#endif
 356        .driver = {
 357                .name   = "mmp-camera",
 358                .owner  = THIS_MODULE
 359        }
 360};
 361
 362
 363static int __init mmpcam_init_module(void)
 364{
 365        mutex_init(&mmpcam_devices_lock);
 366        return platform_driver_register(&mmpcam_driver);
 367}
 368
 369static void __exit mmpcam_exit_module(void)
 370{
 371        platform_driver_unregister(&mmpcam_driver);
 372        /*
 373         * platform_driver_unregister() should have emptied the list
 374         */
 375        if (!list_empty(&mmpcam_devices))
 376                printk(KERN_ERR "mmp_camera leaving devices behind\n");
 377}
 378
 379module_init(mmpcam_init_module);
 380module_exit(mmpcam_exit_module);
 381