root/drivers/media/i2c/ov5647.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. to_state
  2. ov5647_write
  3. ov5647_read
  4. ov5647_write_array
  5. ov5647_set_virtual_channel
  6. ov5647_stream_on
  7. ov5647_stream_off
  8. set_sw_standby
  9. __sensor_init
  10. ov5647_sensor_power
  11. ov5647_sensor_get_register
  12. ov5647_sensor_set_register
  13. ov5647_s_stream
  14. ov5647_enum_mbus_code
  15. ov5647_detect
  16. ov5647_open
  17. ov5647_parse_dt
  18. ov5647_probe
  19. ov5647_remove

   1 /*
   2  * A V4L2 driver for OmniVision OV5647 cameras.
   3  *
   4  * Based on Samsung S5K6AAFX SXGA 1/6" 1.3M CMOS Image Sensor driver
   5  * Copyright (C) 2011 Sylwester Nawrocki <s.nawrocki@samsung.com>
   6  *
   7  * Based on Omnivision OV7670 Camera Driver
   8  * Copyright (C) 2006-7 Jonathan Corbet <corbet@lwn.net>
   9  *
  10  * Copyright (C) 2016, Synopsys, Inc.
  11  *
  12  * This program is free software; you can redistribute it and/or
  13  * modify it under the terms of the GNU General Public License as
  14  * published by the Free Software Foundation version 2.
  15  *
  16  * This program is distributed .as is. WITHOUT ANY WARRANTY of any
  17  * kind, whether express or implied; without even the implied warranty
  18  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  19  * GNU General Public License for more details.
  20  */
  21 
  22 #include <linux/clk.h>
  23 #include <linux/delay.h>
  24 #include <linux/i2c.h>
  25 #include <linux/init.h>
  26 #include <linux/io.h>
  27 #include <linux/module.h>
  28 #include <linux/of_graph.h>
  29 #include <linux/slab.h>
  30 #include <linux/videodev2.h>
  31 #include <media/v4l2-device.h>
  32 #include <media/v4l2-fwnode.h>
  33 #include <media/v4l2-image-sizes.h>
  34 #include <media/v4l2-mediabus.h>
  35 
  36 #define SENSOR_NAME "ov5647"
  37 
  38 #define MIPI_CTRL00_CLOCK_LANE_GATE             BIT(5)
  39 #define MIPI_CTRL00_BUS_IDLE                    BIT(2)
  40 #define MIPI_CTRL00_CLOCK_LANE_DISABLE          BIT(0)
  41 
  42 #define OV5647_SW_STANDBY               0x0100
  43 #define OV5647_SW_RESET                 0x0103
  44 #define OV5647_REG_CHIPID_H             0x300A
  45 #define OV5647_REG_CHIPID_L             0x300B
  46 #define OV5640_REG_PAD_OUT              0x300D
  47 #define OV5647_REG_FRAME_OFF_NUMBER     0x4202
  48 #define OV5647_REG_MIPI_CTRL00          0x4800
  49 #define OV5647_REG_MIPI_CTRL14          0x4814
  50 
  51 #define REG_TERM 0xfffe
  52 #define VAL_TERM 0xfe
  53 #define REG_DLY  0xffff
  54 
  55 #define OV5647_ROW_START                0x01
  56 #define OV5647_ROW_START_MIN            0
  57 #define OV5647_ROW_START_MAX            2004
  58 #define OV5647_ROW_START_DEF            54
  59 
  60 #define OV5647_COLUMN_START             0x02
  61 #define OV5647_COLUMN_START_MIN         0
  62 #define OV5647_COLUMN_START_MAX         2750
  63 #define OV5647_COLUMN_START_DEF         16
  64 
  65 #define OV5647_WINDOW_HEIGHT            0x03
  66 #define OV5647_WINDOW_HEIGHT_MIN        2
  67 #define OV5647_WINDOW_HEIGHT_MAX        2006
  68 #define OV5647_WINDOW_HEIGHT_DEF        1944
  69 
  70 #define OV5647_WINDOW_WIDTH             0x04
  71 #define OV5647_WINDOW_WIDTH_MIN         2
  72 #define OV5647_WINDOW_WIDTH_MAX         2752
  73 #define OV5647_WINDOW_WIDTH_DEF         2592
  74 
  75 struct regval_list {
  76         u16 addr;
  77         u8 data;
  78 };
  79 
  80 struct ov5647 {
  81         struct v4l2_subdev              sd;
  82         struct media_pad                pad;
  83         struct mutex                    lock;
  84         struct v4l2_mbus_framefmt       format;
  85         unsigned int                    width;
  86         unsigned int                    height;
  87         int                             power_count;
  88         struct clk                      *xclk;
  89 };
  90 
  91 static inline struct ov5647 *to_state(struct v4l2_subdev *sd)
  92 {
  93         return container_of(sd, struct ov5647, sd);
  94 }
  95 
  96 static struct regval_list sensor_oe_disable_regs[] = {
  97         {0x3000, 0x00},
  98         {0x3001, 0x00},
  99         {0x3002, 0x00},
 100 };
 101 
 102 static struct regval_list sensor_oe_enable_regs[] = {
 103         {0x3000, 0x0f},
 104         {0x3001, 0xff},
 105         {0x3002, 0xe4},
 106 };
 107 
 108 static struct regval_list ov5647_640x480[] = {
 109         {0x0100, 0x00},
 110         {0x0103, 0x01},
 111         {0x3034, 0x08},
 112         {0x3035, 0x21},
 113         {0x3036, 0x46},
 114         {0x303c, 0x11},
 115         {0x3106, 0xf5},
 116         {0x3821, 0x07},
 117         {0x3820, 0x41},
 118         {0x3827, 0xec},
 119         {0x370c, 0x0f},
 120         {0x3612, 0x59},
 121         {0x3618, 0x00},
 122         {0x5000, 0x06},
 123         {0x5001, 0x01},
 124         {0x5002, 0x41},
 125         {0x5003, 0x08},
 126         {0x5a00, 0x08},
 127         {0x3000, 0x00},
 128         {0x3001, 0x00},
 129         {0x3002, 0x00},
 130         {0x3016, 0x08},
 131         {0x3017, 0xe0},
 132         {0x3018, 0x44},
 133         {0x301c, 0xf8},
 134         {0x301d, 0xf0},
 135         {0x3a18, 0x00},
 136         {0x3a19, 0xf8},
 137         {0x3c01, 0x80},
 138         {0x3b07, 0x0c},
 139         {0x380c, 0x07},
 140         {0x380d, 0x68},
 141         {0x380e, 0x03},
 142         {0x380f, 0xd8},
 143         {0x3814, 0x31},
 144         {0x3815, 0x31},
 145         {0x3708, 0x64},
 146         {0x3709, 0x52},
 147         {0x3808, 0x02},
 148         {0x3809, 0x80},
 149         {0x380a, 0x01},
 150         {0x380b, 0xE0},
 151         {0x3801, 0x00},
 152         {0x3802, 0x00},
 153         {0x3803, 0x00},
 154         {0x3804, 0x0a},
 155         {0x3805, 0x3f},
 156         {0x3806, 0x07},
 157         {0x3807, 0xa1},
 158         {0x3811, 0x08},
 159         {0x3813, 0x02},
 160         {0x3630, 0x2e},
 161         {0x3632, 0xe2},
 162         {0x3633, 0x23},
 163         {0x3634, 0x44},
 164         {0x3636, 0x06},
 165         {0x3620, 0x64},
 166         {0x3621, 0xe0},
 167         {0x3600, 0x37},
 168         {0x3704, 0xa0},
 169         {0x3703, 0x5a},
 170         {0x3715, 0x78},
 171         {0x3717, 0x01},
 172         {0x3731, 0x02},
 173         {0x370b, 0x60},
 174         {0x3705, 0x1a},
 175         {0x3f05, 0x02},
 176         {0x3f06, 0x10},
 177         {0x3f01, 0x0a},
 178         {0x3a08, 0x01},
 179         {0x3a09, 0x27},
 180         {0x3a0a, 0x00},
 181         {0x3a0b, 0xf6},
 182         {0x3a0d, 0x04},
 183         {0x3a0e, 0x03},
 184         {0x3a0f, 0x58},
 185         {0x3a10, 0x50},
 186         {0x3a1b, 0x58},
 187         {0x3a1e, 0x50},
 188         {0x3a11, 0x60},
 189         {0x3a1f, 0x28},
 190         {0x4001, 0x02},
 191         {0x4004, 0x02},
 192         {0x4000, 0x09},
 193         {0x4837, 0x24},
 194         {0x4050, 0x6e},
 195         {0x4051, 0x8f},
 196         {0x0100, 0x01},
 197 };
 198 
 199 static int ov5647_write(struct v4l2_subdev *sd, u16 reg, u8 val)
 200 {
 201         int ret;
 202         unsigned char data[3] = { reg >> 8, reg & 0xff, val};
 203         struct i2c_client *client = v4l2_get_subdevdata(sd);
 204 
 205         ret = i2c_master_send(client, data, 3);
 206         if (ret < 0)
 207                 dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
 208                                 __func__, reg);
 209 
 210         return ret;
 211 }
 212 
 213 static int ov5647_read(struct v4l2_subdev *sd, u16 reg, u8 *val)
 214 {
 215         int ret;
 216         unsigned char data_w[2] = { reg >> 8, reg & 0xff };
 217         struct i2c_client *client = v4l2_get_subdevdata(sd);
 218 
 219         ret = i2c_master_send(client, data_w, 2);
 220         if (ret < 0) {
 221                 dev_dbg(&client->dev, "%s: i2c write error, reg: %x\n",
 222                         __func__, reg);
 223                 return ret;
 224         }
 225 
 226         ret = i2c_master_recv(client, val, 1);
 227         if (ret < 0)
 228                 dev_dbg(&client->dev, "%s: i2c read error, reg: %x\n",
 229                                 __func__, reg);
 230 
 231         return ret;
 232 }
 233 
 234 static int ov5647_write_array(struct v4l2_subdev *sd,
 235                                 struct regval_list *regs, int array_size)
 236 {
 237         int i, ret;
 238 
 239         for (i = 0; i < array_size; i++) {
 240                 ret = ov5647_write(sd, regs[i].addr, regs[i].data);
 241                 if (ret < 0)
 242                         return ret;
 243         }
 244 
 245         return 0;
 246 }
 247 
 248 static int ov5647_set_virtual_channel(struct v4l2_subdev *sd, int channel)
 249 {
 250         u8 channel_id;
 251         int ret;
 252 
 253         ret = ov5647_read(sd, OV5647_REG_MIPI_CTRL14, &channel_id);
 254         if (ret < 0)
 255                 return ret;
 256 
 257         channel_id &= ~(3 << 6);
 258         return ov5647_write(sd, OV5647_REG_MIPI_CTRL14, channel_id | (channel << 6));
 259 }
 260 
 261 static int ov5647_stream_on(struct v4l2_subdev *sd)
 262 {
 263         int ret;
 264 
 265         ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_BUS_IDLE);
 266         if (ret < 0)
 267                 return ret;
 268 
 269         ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x00);
 270         if (ret < 0)
 271                 return ret;
 272 
 273         return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x00);
 274 }
 275 
 276 static int ov5647_stream_off(struct v4l2_subdev *sd)
 277 {
 278         int ret;
 279 
 280         ret = ov5647_write(sd, OV5647_REG_MIPI_CTRL00, MIPI_CTRL00_CLOCK_LANE_GATE
 281                            | MIPI_CTRL00_BUS_IDLE | MIPI_CTRL00_CLOCK_LANE_DISABLE);
 282         if (ret < 0)
 283                 return ret;
 284 
 285         ret = ov5647_write(sd, OV5647_REG_FRAME_OFF_NUMBER, 0x0f);
 286         if (ret < 0)
 287                 return ret;
 288 
 289         return ov5647_write(sd, OV5640_REG_PAD_OUT, 0x01);
 290 }
 291 
 292 static int set_sw_standby(struct v4l2_subdev *sd, bool standby)
 293 {
 294         int ret;
 295         u8 rdval;
 296 
 297         ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
 298         if (ret < 0)
 299                 return ret;
 300 
 301         if (standby)
 302                 rdval &= ~0x01;
 303         else
 304                 rdval |= 0x01;
 305 
 306         return ov5647_write(sd, OV5647_SW_STANDBY, rdval);
 307 }
 308 
 309 static int __sensor_init(struct v4l2_subdev *sd)
 310 {
 311         int ret;
 312         u8 resetval, rdval;
 313         struct i2c_client *client = v4l2_get_subdevdata(sd);
 314 
 315         ret = ov5647_read(sd, OV5647_SW_STANDBY, &rdval);
 316         if (ret < 0)
 317                 return ret;
 318 
 319         ret = ov5647_write_array(sd, ov5647_640x480,
 320                                         ARRAY_SIZE(ov5647_640x480));
 321         if (ret < 0) {
 322                 dev_err(&client->dev, "write sensor default regs error\n");
 323                 return ret;
 324         }
 325 
 326         ret = ov5647_set_virtual_channel(sd, 0);
 327         if (ret < 0)
 328                 return ret;
 329 
 330         ret = ov5647_read(sd, OV5647_SW_STANDBY, &resetval);
 331         if (ret < 0)
 332                 return ret;
 333 
 334         if (!(resetval & 0x01)) {
 335                 dev_err(&client->dev, "Device was in SW standby");
 336                 ret = ov5647_write(sd, OV5647_SW_STANDBY, 0x01);
 337                 if (ret < 0)
 338                         return ret;
 339         }
 340 
 341         /*
 342          * stream off to make the clock lane into LP-11 state.
 343          */
 344         return ov5647_stream_off(sd);
 345 }
 346 
 347 static int ov5647_sensor_power(struct v4l2_subdev *sd, int on)
 348 {
 349         int ret = 0;
 350         struct ov5647 *ov5647 = to_state(sd);
 351         struct i2c_client *client = v4l2_get_subdevdata(sd);
 352 
 353         mutex_lock(&ov5647->lock);
 354 
 355         if (on && !ov5647->power_count) {
 356                 dev_dbg(&client->dev, "OV5647 power on\n");
 357 
 358                 ret = clk_prepare_enable(ov5647->xclk);
 359                 if (ret < 0) {
 360                         dev_err(&client->dev, "clk prepare enable failed\n");
 361                         goto out;
 362                 }
 363 
 364                 ret = ov5647_write_array(sd, sensor_oe_enable_regs,
 365                                 ARRAY_SIZE(sensor_oe_enable_regs));
 366                 if (ret < 0) {
 367                         clk_disable_unprepare(ov5647->xclk);
 368                         dev_err(&client->dev,
 369                                 "write sensor_oe_enable_regs error\n");
 370                         goto out;
 371                 }
 372 
 373                 ret = __sensor_init(sd);
 374                 if (ret < 0) {
 375                         clk_disable_unprepare(ov5647->xclk);
 376                         dev_err(&client->dev,
 377                                 "Camera not available, check Power\n");
 378                         goto out;
 379                 }
 380         } else if (!on && ov5647->power_count == 1) {
 381                 dev_dbg(&client->dev, "OV5647 power off\n");
 382 
 383                 ret = ov5647_write_array(sd, sensor_oe_disable_regs,
 384                                 ARRAY_SIZE(sensor_oe_disable_regs));
 385 
 386                 if (ret < 0)
 387                         dev_dbg(&client->dev, "disable oe failed\n");
 388 
 389                 ret = set_sw_standby(sd, true);
 390 
 391                 if (ret < 0)
 392                         dev_dbg(&client->dev, "soft stby failed\n");
 393 
 394                 clk_disable_unprepare(ov5647->xclk);
 395         }
 396 
 397         /* Update the power count. */
 398         ov5647->power_count += on ? 1 : -1;
 399         WARN_ON(ov5647->power_count < 0);
 400 
 401 out:
 402         mutex_unlock(&ov5647->lock);
 403 
 404         return ret;
 405 }
 406 
 407 #ifdef CONFIG_VIDEO_ADV_DEBUG
 408 static int ov5647_sensor_get_register(struct v4l2_subdev *sd,
 409                                 struct v4l2_dbg_register *reg)
 410 {
 411         u8 val;
 412         int ret;
 413 
 414         ret = ov5647_read(sd, reg->reg & 0xff, &val);
 415         if (ret < 0)
 416                 return ret;
 417 
 418         reg->val = val;
 419         reg->size = 1;
 420 
 421         return 0;
 422 }
 423 
 424 static int ov5647_sensor_set_register(struct v4l2_subdev *sd,
 425                                 const struct v4l2_dbg_register *reg)
 426 {
 427         return ov5647_write(sd, reg->reg & 0xff, reg->val & 0xff);
 428 }
 429 #endif
 430 
 431 /*
 432  * Subdev core operations registration
 433  */
 434 static const struct v4l2_subdev_core_ops ov5647_subdev_core_ops = {
 435         .s_power                = ov5647_sensor_power,
 436 #ifdef CONFIG_VIDEO_ADV_DEBUG
 437         .g_register             = ov5647_sensor_get_register,
 438         .s_register             = ov5647_sensor_set_register,
 439 #endif
 440 };
 441 
 442 static int ov5647_s_stream(struct v4l2_subdev *sd, int enable)
 443 {
 444         if (enable)
 445                 return ov5647_stream_on(sd);
 446         else
 447                 return ov5647_stream_off(sd);
 448 }
 449 
 450 static const struct v4l2_subdev_video_ops ov5647_subdev_video_ops = {
 451         .s_stream =             ov5647_s_stream,
 452 };
 453 
 454 static int ov5647_enum_mbus_code(struct v4l2_subdev *sd,
 455                                 struct v4l2_subdev_pad_config *cfg,
 456                                 struct v4l2_subdev_mbus_code_enum *code)
 457 {
 458         if (code->index > 0)
 459                 return -EINVAL;
 460 
 461         code->code = MEDIA_BUS_FMT_SBGGR8_1X8;
 462 
 463         return 0;
 464 }
 465 
 466 static const struct v4l2_subdev_pad_ops ov5647_subdev_pad_ops = {
 467         .enum_mbus_code = ov5647_enum_mbus_code,
 468 };
 469 
 470 static const struct v4l2_subdev_ops ov5647_subdev_ops = {
 471         .core           = &ov5647_subdev_core_ops,
 472         .video          = &ov5647_subdev_video_ops,
 473         .pad            = &ov5647_subdev_pad_ops,
 474 };
 475 
 476 static int ov5647_detect(struct v4l2_subdev *sd)
 477 {
 478         u8 read;
 479         int ret;
 480         struct i2c_client *client = v4l2_get_subdevdata(sd);
 481 
 482         ret = ov5647_write(sd, OV5647_SW_RESET, 0x01);
 483         if (ret < 0)
 484                 return ret;
 485 
 486         ret = ov5647_read(sd, OV5647_REG_CHIPID_H, &read);
 487         if (ret < 0)
 488                 return ret;
 489 
 490         if (read != 0x56) {
 491                 dev_err(&client->dev, "ID High expected 0x56 got %x", read);
 492                 return -ENODEV;
 493         }
 494 
 495         ret = ov5647_read(sd, OV5647_REG_CHIPID_L, &read);
 496         if (ret < 0)
 497                 return ret;
 498 
 499         if (read != 0x47) {
 500                 dev_err(&client->dev, "ID Low expected 0x47 got %x", read);
 501                 return -ENODEV;
 502         }
 503 
 504         return ov5647_write(sd, OV5647_SW_RESET, 0x00);
 505 }
 506 
 507 static int ov5647_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
 508 {
 509         struct v4l2_mbus_framefmt *format =
 510                                 v4l2_subdev_get_try_format(sd, fh->pad, 0);
 511         struct v4l2_rect *crop =
 512                                 v4l2_subdev_get_try_crop(sd, fh->pad, 0);
 513 
 514         crop->left = OV5647_COLUMN_START_DEF;
 515         crop->top = OV5647_ROW_START_DEF;
 516         crop->width = OV5647_WINDOW_WIDTH_DEF;
 517         crop->height = OV5647_WINDOW_HEIGHT_DEF;
 518 
 519         format->code = MEDIA_BUS_FMT_SBGGR8_1X8;
 520 
 521         format->width = OV5647_WINDOW_WIDTH_DEF;
 522         format->height = OV5647_WINDOW_HEIGHT_DEF;
 523         format->field = V4L2_FIELD_NONE;
 524         format->colorspace = V4L2_COLORSPACE_SRGB;
 525 
 526         return 0;
 527 }
 528 
 529 static const struct v4l2_subdev_internal_ops ov5647_subdev_internal_ops = {
 530         .open = ov5647_open,
 531 };
 532 
 533 static int ov5647_parse_dt(struct device_node *np)
 534 {
 535         struct v4l2_fwnode_endpoint bus_cfg = { .bus_type = 0 };
 536         struct device_node *ep;
 537 
 538         int ret;
 539 
 540         ep = of_graph_get_next_endpoint(np, NULL);
 541         if (!ep)
 542                 return -EINVAL;
 543 
 544         ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
 545 
 546         of_node_put(ep);
 547         return ret;
 548 }
 549 
 550 static int ov5647_probe(struct i2c_client *client)
 551 {
 552         struct device *dev = &client->dev;
 553         struct ov5647 *sensor;
 554         int ret;
 555         struct v4l2_subdev *sd;
 556         struct device_node *np = client->dev.of_node;
 557         u32 xclk_freq;
 558 
 559         sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
 560         if (!sensor)
 561                 return -ENOMEM;
 562 
 563         if (IS_ENABLED(CONFIG_OF) && np) {
 564                 ret = ov5647_parse_dt(np);
 565                 if (ret) {
 566                         dev_err(dev, "DT parsing error: %d\n", ret);
 567                         return ret;
 568                 }
 569         }
 570 
 571         /* get system clock (xclk) */
 572         sensor->xclk = devm_clk_get(dev, NULL);
 573         if (IS_ERR(sensor->xclk)) {
 574                 dev_err(dev, "could not get xclk");
 575                 return PTR_ERR(sensor->xclk);
 576         }
 577 
 578         xclk_freq = clk_get_rate(sensor->xclk);
 579         if (xclk_freq != 25000000) {
 580                 dev_err(dev, "Unsupported clock frequency: %u\n", xclk_freq);
 581                 return -EINVAL;
 582         }
 583 
 584         mutex_init(&sensor->lock);
 585 
 586         sd = &sensor->sd;
 587         v4l2_i2c_subdev_init(sd, client, &ov5647_subdev_ops);
 588         sensor->sd.internal_ops = &ov5647_subdev_internal_ops;
 589         sensor->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
 590 
 591         sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
 592         sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
 593         ret = media_entity_pads_init(&sd->entity, 1, &sensor->pad);
 594         if (ret < 0)
 595                 goto mutex_remove;
 596 
 597         ret = ov5647_detect(sd);
 598         if (ret < 0)
 599                 goto error;
 600 
 601         ret = v4l2_async_register_subdev(sd);
 602         if (ret < 0)
 603                 goto error;
 604 
 605         dev_dbg(dev, "OmniVision OV5647 camera driver probed\n");
 606         return 0;
 607 error:
 608         media_entity_cleanup(&sd->entity);
 609 mutex_remove:
 610         mutex_destroy(&sensor->lock);
 611         return ret;
 612 }
 613 
 614 static int ov5647_remove(struct i2c_client *client)
 615 {
 616         struct v4l2_subdev *sd = i2c_get_clientdata(client);
 617         struct ov5647 *ov5647 = to_state(sd);
 618 
 619         v4l2_async_unregister_subdev(&ov5647->sd);
 620         media_entity_cleanup(&ov5647->sd.entity);
 621         v4l2_device_unregister_subdev(sd);
 622         mutex_destroy(&ov5647->lock);
 623 
 624         return 0;
 625 }
 626 
 627 static const struct i2c_device_id ov5647_id[] = {
 628         { "ov5647", 0 },
 629         { }
 630 };
 631 MODULE_DEVICE_TABLE(i2c, ov5647_id);
 632 
 633 #if IS_ENABLED(CONFIG_OF)
 634 static const struct of_device_id ov5647_of_match[] = {
 635         { .compatible = "ovti,ov5647" },
 636         { /* sentinel */ },
 637 };
 638 MODULE_DEVICE_TABLE(of, ov5647_of_match);
 639 #endif
 640 
 641 static struct i2c_driver ov5647_driver = {
 642         .driver = {
 643                 .of_match_table = of_match_ptr(ov5647_of_match),
 644                 .name   = SENSOR_NAME,
 645         },
 646         .probe_new      = ov5647_probe,
 647         .remove         = ov5647_remove,
 648         .id_table       = ov5647_id,
 649 };
 650 
 651 module_i2c_driver(ov5647_driver);
 652 
 653 MODULE_AUTHOR("Ramiro Oliveira <roliveir@synopsys.com>");
 654 MODULE_DESCRIPTION("A low-level driver for OmniVision ov5647 sensors");
 655 MODULE_LICENSE("GPL v2");

/* [<][>][^][v][top][bottom][index][help] */