linux/drivers/media/platform/exynos4-is/fimc-is-sensor.c
<<
>>
Prefs
   1/*
   2 * Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver
   3 *
   4 * Copyright (C) 2013 Samsung Electronics Co., Ltd.
   5 *
   6 * Author: Sylwester Nawrocki <s.nawrocki@samsung.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 */
  12#include <linux/delay.h>
  13#include <linux/device.h>
  14#include <linux/errno.h>
  15#include <linux/gpio.h>
  16#include <linux/i2c.h>
  17#include <linux/kernel.h>
  18#include <linux/module.h>
  19#include <linux/of_gpio.h>
  20#include <linux/pm_runtime.h>
  21#include <linux/regulator/consumer.h>
  22#include <linux/slab.h>
  23#include <media/v4l2-subdev.h>
  24
  25#include "fimc-is.h"
  26#include "fimc-is-sensor.h"
  27
  28#define DRIVER_NAME "FIMC-IS-SENSOR"
  29
  30static const char * const sensor_supply_names[] = {
  31        "svdda",
  32        "svddio",
  33};
  34
  35static const struct v4l2_mbus_framefmt fimc_is_sensor_formats[] = {
  36        {
  37                .code = V4L2_MBUS_FMT_SGRBG10_1X10,
  38                .colorspace = V4L2_COLORSPACE_SRGB,
  39                .field = V4L2_FIELD_NONE,
  40        }
  41};
  42
  43static const struct v4l2_mbus_framefmt *find_sensor_format(
  44        struct v4l2_mbus_framefmt *mf)
  45{
  46        int i;
  47
  48        for (i = 0; i < ARRAY_SIZE(fimc_is_sensor_formats); i++)
  49                if (mf->code == fimc_is_sensor_formats[i].code)
  50                        return &fimc_is_sensor_formats[i];
  51
  52        return &fimc_is_sensor_formats[0];
  53}
  54
  55static int fimc_is_sensor_enum_mbus_code(struct v4l2_subdev *sd,
  56                                  struct v4l2_subdev_fh *fh,
  57                                  struct v4l2_subdev_mbus_code_enum *code)
  58{
  59        if (code->index >= ARRAY_SIZE(fimc_is_sensor_formats))
  60                return -EINVAL;
  61
  62        code->code = fimc_is_sensor_formats[code->index].code;
  63        return 0;
  64}
  65
  66static void fimc_is_sensor_try_format(struct fimc_is_sensor *sensor,
  67                                      struct v4l2_mbus_framefmt *mf)
  68{
  69        const struct sensor_drv_data *dd = sensor->drvdata;
  70        const struct v4l2_mbus_framefmt *fmt;
  71
  72        fmt = find_sensor_format(mf);
  73        mf->code = fmt->code;
  74        v4l_bound_align_image(&mf->width, 16 + 8, dd->width, 0,
  75                              &mf->height, 12 + 8, dd->height, 0, 0);
  76}
  77
  78static struct v4l2_mbus_framefmt *__fimc_is_sensor_get_format(
  79                struct fimc_is_sensor *sensor, struct v4l2_subdev_fh *fh,
  80                u32 pad, enum v4l2_subdev_format_whence which)
  81{
  82        if (which == V4L2_SUBDEV_FORMAT_TRY)
  83                return fh ? v4l2_subdev_get_try_format(fh, pad) : NULL;
  84
  85        return &sensor->format;
  86}
  87
  88static int fimc_is_sensor_set_fmt(struct v4l2_subdev *sd,
  89                                  struct v4l2_subdev_fh *fh,
  90                                  struct v4l2_subdev_format *fmt)
  91{
  92        struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
  93        struct v4l2_mbus_framefmt *mf;
  94
  95        fimc_is_sensor_try_format(sensor, &fmt->format);
  96
  97        mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which);
  98        if (mf) {
  99                mutex_lock(&sensor->lock);
 100                if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
 101                        *mf = fmt->format;
 102                mutex_unlock(&sensor->lock);
 103        }
 104        return 0;
 105}
 106
 107static int fimc_is_sensor_get_fmt(struct v4l2_subdev *sd,
 108                                  struct v4l2_subdev_fh *fh,
 109                                  struct v4l2_subdev_format *fmt)
 110{
 111        struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
 112        struct v4l2_mbus_framefmt *mf;
 113
 114        mf = __fimc_is_sensor_get_format(sensor, fh, fmt->pad, fmt->which);
 115
 116        mutex_lock(&sensor->lock);
 117        fmt->format = *mf;
 118        mutex_unlock(&sensor->lock);
 119        return 0;
 120}
 121
 122static struct v4l2_subdev_pad_ops fimc_is_sensor_pad_ops = {
 123        .enum_mbus_code = fimc_is_sensor_enum_mbus_code,
 124        .get_fmt        = fimc_is_sensor_get_fmt,
 125        .set_fmt        = fimc_is_sensor_set_fmt,
 126};
 127
 128static int fimc_is_sensor_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 129{
 130        struct v4l2_mbus_framefmt *format = v4l2_subdev_get_try_format(fh, 0);
 131
 132        *format         = fimc_is_sensor_formats[0];
 133        format->width   = FIMC_IS_SENSOR_DEF_PIX_WIDTH;
 134        format->height  = FIMC_IS_SENSOR_DEF_PIX_HEIGHT;
 135
 136        return 0;
 137}
 138
 139static const struct v4l2_subdev_internal_ops fimc_is_sensor_sd_internal_ops = {
 140        .open = fimc_is_sensor_open,
 141};
 142
 143static int fimc_is_sensor_s_power(struct v4l2_subdev *sd, int on)
 144{
 145        struct fimc_is_sensor *sensor = sd_to_fimc_is_sensor(sd);
 146        int gpio = sensor->gpio_reset;
 147        int ret;
 148
 149        if (on) {
 150                ret = pm_runtime_get(sensor->dev);
 151                if (ret < 0)
 152                        return ret;
 153
 154                ret = regulator_bulk_enable(SENSOR_NUM_SUPPLIES,
 155                                            sensor->supplies);
 156                if (ret < 0) {
 157                        pm_runtime_put(sensor->dev);
 158                        return ret;
 159                }
 160                if (gpio_is_valid(gpio)) {
 161                        gpio_set_value(gpio, 1);
 162                        usleep_range(600, 800);
 163                        gpio_set_value(gpio, 0);
 164                        usleep_range(10000, 11000);
 165                        gpio_set_value(gpio, 1);
 166                }
 167
 168                /* A delay needed for the sensor initialization. */
 169                msleep(20);
 170        } else {
 171                if (gpio_is_valid(gpio))
 172                        gpio_set_value(gpio, 0);
 173
 174                ret = regulator_bulk_disable(SENSOR_NUM_SUPPLIES,
 175                                             sensor->supplies);
 176                if (!ret)
 177                        pm_runtime_put(sensor->dev);
 178        }
 179
 180        pr_info("%s:%d: on: %d, ret: %d\n", __func__, __LINE__, on, ret);
 181
 182        return ret;
 183}
 184
 185static struct v4l2_subdev_core_ops fimc_is_sensor_core_ops = {
 186        .s_power = fimc_is_sensor_s_power,
 187};
 188
 189static struct v4l2_subdev_ops fimc_is_sensor_subdev_ops = {
 190        .core = &fimc_is_sensor_core_ops,
 191        .pad = &fimc_is_sensor_pad_ops,
 192};
 193
 194static const struct of_device_id fimc_is_sensor_of_match[];
 195
 196static int fimc_is_sensor_probe(struct i2c_client *client,
 197                                const struct i2c_device_id *id)
 198{
 199        struct device *dev = &client->dev;
 200        struct fimc_is_sensor *sensor;
 201        const struct of_device_id *of_id;
 202        struct v4l2_subdev *sd;
 203        int gpio, i, ret;
 204
 205        sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
 206        if (!sensor)
 207                return -ENOMEM;
 208
 209        mutex_init(&sensor->lock);
 210        sensor->gpio_reset = -EINVAL;
 211
 212        gpio = of_get_gpio_flags(dev->of_node, 0, NULL);
 213        if (gpio_is_valid(gpio)) {
 214                ret = devm_gpio_request_one(dev, gpio, GPIOF_OUT_INIT_LOW,
 215                                                        DRIVER_NAME);
 216                if (ret < 0)
 217                        return ret;
 218        }
 219        sensor->gpio_reset = gpio;
 220
 221        for (i = 0; i < SENSOR_NUM_SUPPLIES; i++)
 222                sensor->supplies[i].supply = sensor_supply_names[i];
 223
 224        ret = devm_regulator_bulk_get(&client->dev, SENSOR_NUM_SUPPLIES,
 225                                      sensor->supplies);
 226        if (ret < 0)
 227                return ret;
 228
 229        of_id = of_match_node(fimc_is_sensor_of_match, dev->of_node);
 230        if (!of_id)
 231                return -ENODEV;
 232
 233        sensor->drvdata = of_id->data;
 234        sensor->dev = dev;
 235
 236        sd = &sensor->subdev;
 237        v4l2_i2c_subdev_init(sd, client, &fimc_is_sensor_subdev_ops);
 238        snprintf(sd->name, sizeof(sd->name), sensor->drvdata->subdev_name);
 239        sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 240
 241        sensor->format.code = fimc_is_sensor_formats[0].code;
 242        sensor->format.width = FIMC_IS_SENSOR_DEF_PIX_WIDTH;
 243        sensor->format.height = FIMC_IS_SENSOR_DEF_PIX_HEIGHT;
 244
 245        sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
 246        ret = media_entity_init(&sd->entity, 1, &sensor->pad, 0);
 247        if (ret < 0)
 248                return ret;
 249
 250        pm_runtime_no_callbacks(dev);
 251        pm_runtime_enable(dev);
 252
 253        return ret;
 254}
 255
 256static int fimc_is_sensor_remove(struct i2c_client *client)
 257{
 258        struct v4l2_subdev *sd = i2c_get_clientdata(client);
 259        media_entity_cleanup(&sd->entity);
 260        return 0;
 261}
 262
 263static const struct i2c_device_id fimc_is_sensor_ids[] = {
 264        { }
 265};
 266
 267static const struct sensor_drv_data s5k6a3_drvdata = {
 268        .id             = FIMC_IS_SENSOR_ID_S5K6A3,
 269        .subdev_name    = "S5K6A3",
 270        .width          = S5K6A3_SENSOR_WIDTH,
 271        .height         = S5K6A3_SENSOR_HEIGHT,
 272};
 273
 274static const struct of_device_id fimc_is_sensor_of_match[] = {
 275        {
 276                .compatible     = "samsung,s5k6a3",
 277                .data           = &s5k6a3_drvdata,
 278        },
 279        {  }
 280};
 281
 282static struct i2c_driver fimc_is_sensor_driver = {
 283        .driver = {
 284                .of_match_table = fimc_is_sensor_of_match,
 285                .name           = DRIVER_NAME,
 286                .owner          = THIS_MODULE,
 287        },
 288        .probe          = fimc_is_sensor_probe,
 289        .remove         = fimc_is_sensor_remove,
 290        .id_table       = fimc_is_sensor_ids,
 291};
 292
 293int fimc_is_register_sensor_driver(void)
 294{
 295        return i2c_add_driver(&fimc_is_sensor_driver);
 296}
 297
 298void fimc_is_unregister_sensor_driver(void)
 299{
 300        i2c_del_driver(&fimc_is_sensor_driver);
 301}
 302
 303MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
 304MODULE_DESCRIPTION("Exynos4x12 FIMC-IS image sensor subdev driver");
 305MODULE_LICENSE("GPL");
 306