int em28xx_init_camera(struct em28xx *dev) { char clk_name[V4L2_SUBDEV_NAME_SIZE]; struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; struct em28xx_v4l2 *v4l2 = dev->v4l2; int ret = 0; v4l2_clk_name_i2c(clk_name, sizeof(clk_name), i2c_adapter_id(adap), client->addr); v4l2->clk = v4l2_clk_register_fixed(clk_name, -EINVAL); if (IS_ERR(v4l2->clk)) return PTR_ERR(v4l2->clk); switch (dev->em28xx_sensor) { case EM28XX_MT9V011: { struct mt9v011_platform_data pdata; struct i2c_board_info mt9v011_info = { .type = "mt9v011", .addr = client->addr, .platform_data = &pdata, }; v4l2->sensor_xres = 640; v4l2->sensor_yres = 480; /* * FIXME: mt9v011 uses I2S speed as xtal clk - at least with * the Silvercrest cam I have here for testing - for higher * resolutions, a high clock cause horizontal artifacts, so we * need to use a lower xclk frequency. * Yet, it would be possible to adjust xclk depending on the * desired resolution, since this affects directly the * frame rate. */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); v4l2->sensor_xtal = 4300000; pdata.xtal = v4l2->sensor_xtal; if (NULL == v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, &mt9v011_info, NULL)) { ret = -ENODEV; break; } /* probably means GRGB 16 bit bayer */ v4l2->vinmode = 0x0d; v4l2->vinctl = 0x00; break; } case EM28XX_MT9M001: v4l2->sensor_xres = 1280; v4l2->sensor_yres = 1024; em28xx_initialize_mt9m001(dev); /* probably means BGGR 16 bit bayer */ v4l2->vinmode = 0x0c; v4l2->vinctl = 0x00; break; case EM28XX_MT9M111: v4l2->sensor_xres = 640; v4l2->sensor_yres = 512; dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); em28xx_initialize_mt9m111(dev); v4l2->vinmode = 0x0a; v4l2->vinctl = 0x00; break; case EM28XX_OV2640: { struct v4l2_subdev *subdev; struct i2c_board_info ov2640_info = { .type = "ov2640", .flags = I2C_CLIENT_SCCB, .addr = client->addr, .platform_data = &camlink, }; struct v4l2_mbus_framefmt fmt; /* * FIXME: sensor supports resolutions up to 1600x1200, but * resolution setting/switching needs to be modified to * - switch sensor output resolution (including further * configuration changes) * - adjust bridge xclk * - disable 16 bit (12 bit) output formats on high resolutions */ v4l2->sensor_xres = 640; v4l2->sensor_yres = 480; subdev = v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, &ov2640_info, NULL); if (NULL == subdev) { ret = -ENODEV; break; } fmt.code = MEDIA_BUS_FMT_YUYV8_2X8; fmt.width = 640; fmt.height = 480; v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt); /* NOTE: for UXGA=1600x1200 switch to 12MHz */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); v4l2->vinmode = 0x08; v4l2->vinctl = 0x00; break; } case EM28XX_NOSENSOR: default: ret = -EINVAL; } if (ret < 0) { v4l2_clk_unregister_fixed(v4l2->clk); v4l2->clk = NULL; } return ret; } EXPORT_SYMBOL_GPL(em28xx_init_camera);
int em28xx_init_camera(struct em28xx *dev) { struct i2c_client *client = &dev->i2c_client[dev->def_i2c_bus]; struct i2c_adapter *adap = &dev->i2c_adap[dev->def_i2c_bus]; struct em28xx_v4l2 *v4l2 = dev->v4l2; switch (dev->em28xx_sensor) { case EM28XX_MT9V011: { struct mt9v011_platform_data pdata; struct i2c_board_info mt9v011_info = { .type = "mt9v011", .addr = client->addr, .platform_data = &pdata, }; v4l2->sensor_xres = 640; v4l2->sensor_yres = 480; /* * FIXME: mt9v011 uses I2S speed as xtal clk - at least with * the Silvercrest cam I have here for testing - for higher * resolutions, a high clock cause horizontal artifacts, so we * need to use a lower xclk frequency. * Yet, it would be possible to adjust xclk depending on the * desired resolution, since this affects directly the * frame rate. */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_4_3MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); v4l2->sensor_xtal = 4300000; pdata.xtal = v4l2->sensor_xtal; if (NULL == v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, &mt9v011_info, NULL)) return -ENODEV; v4l2->vinmode = EM28XX_VINMODE_RGB8_GRBG; v4l2->vinctl = 0x00; break; } case EM28XX_MT9M001: v4l2->sensor_xres = 1280; v4l2->sensor_yres = 1024; em28xx_initialize_mt9m001(dev); v4l2->vinmode = EM28XX_VINMODE_RGB8_BGGR; v4l2->vinctl = 0x00; break; case EM28XX_MT9M111: v4l2->sensor_xres = 640; v4l2->sensor_yres = 512; dev->board.xclk = EM28XX_XCLK_FREQUENCY_48MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); em28xx_initialize_mt9m111(dev); v4l2->vinmode = EM28XX_VINMODE_YUV422_UYVY; v4l2->vinctl = 0x00; break; case EM28XX_OV2640: { struct v4l2_subdev *subdev; struct i2c_board_info ov2640_info = { .type = "ov2640", .flags = I2C_CLIENT_SCCB, .addr = client->addr, }; struct v4l2_subdev_format format = { .which = V4L2_SUBDEV_FORMAT_ACTIVE, }; /* * FIXME: sensor supports resolutions up to 1600x1200, but * resolution setting/switching needs to be modified to * - switch sensor output resolution (including further * configuration changes) * - adjust bridge xclk * - disable 16 bit (12 bit) output formats on high resolutions */ v4l2->sensor_xres = 640; v4l2->sensor_yres = 480; subdev = v4l2_i2c_new_subdev_board(&v4l2->v4l2_dev, adap, &ov2640_info, NULL); if (subdev == NULL) return -ENODEV; format.format.code = MEDIA_BUS_FMT_YUYV8_2X8; format.format.width = 640; format.format.height = 480; v4l2_subdev_call(subdev, pad, set_fmt, NULL, &format); /* NOTE: for UXGA=1600x1200 switch to 12MHz */ dev->board.xclk = EM28XX_XCLK_FREQUENCY_24MHZ; em28xx_write_reg(dev, EM28XX_R0F_XCLK, dev->board.xclk); v4l2->vinmode = EM28XX_VINMODE_YUV422_YUYV; v4l2->vinctl = 0x00; break; } case EM28XX_NOSENSOR: default: return -EINVAL; } return 0; } EXPORT_SYMBOL_GPL(em28xx_init_camera);