@@ -13,9 +13,9 @@
#include <linux/i2c.h>
#include <linux/log2.h>
+#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
-#include <media/soc_camera.h>
/* mt9t031 i2c address 0x5d
* The platform has to define i2c_board_info
@@ -52,33 +52,108 @@
#define MT9T031_VERTICAL_BLANK 25
#define MT9T031_COLUMN_SKIP 32
#define MT9T031_ROW_SKIP 20
+#define MT9T031_DEFAULT_WIDTH 640
+#define MT9T031_DEFAULT_HEIGHT 480
#define MT9T031_BUS_PARAM (SOCAM_PCLK_SAMPLE_RISING | \
SOCAM_PCLK_SAMPLE_FALLING | SOCAM_HSYNC_ACTIVE_HIGH | \
SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_DATA_ACTIVE_HIGH | \
SOCAM_MASTER | SOCAM_DATAWIDTH_10)
-static const struct soc_camera_data_format mt9t031_colour_formats[] = {
+
+/* Debug functions */
+static int debug;
+module_param(debug, bool, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+static const struct v4l2_fmtdesc mt9t031_formats[] = {
+ {
+ .index = 0,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .description = "Bayer (sRGB) 10 bit",
+ .pixelformat = V4L2_PIX_FMT_SGRBG10,
+ },
+};
+static const unsigned int mt9t031_num_formats = ARRAY_SIZE(mt9t031_formats);
+
+static const struct v4l2_queryctrl mt9t031_controls[] = {
{
- .name = "Bayer (sRGB) 10 bit",
- .depth = 10,
- .fourcc = V4L2_PIX_FMT_SGRBG10,
- .colorspace = V4L2_COLORSPACE_SRGB,
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Vertically",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }, {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Horizontally",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }, {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 64,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 255,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
}
};
+static const unsigned int mt9t031_num_controls = ARRAY_SIZE(mt9t031_controls);
struct mt9t031 {
- struct i2c_client *client;
- struct soc_camera_device icd;
+ struct v4l2_subdev sd;
int model; /* V4L2_IDENT_MT9T031* codes from v4l2-chip-ident.h */
unsigned char autoexposure;
u16 xskip;
u16 yskip;
+ u32 width;
+ u32 height;
+ unsigned short x_min; /* Camera capabilities */
+ unsigned short y_min;
+ unsigned short x_current; /* Current window location */
+ unsigned short y_current;
+ unsigned short width_min;
+ unsigned short width_max;
+ unsigned short height_min;
+ unsigned short height_max;
+ unsigned short y_skip_top; /* Lines to skip at the top */
+ unsigned short gain;
+ unsigned short exposure;
};
+static inline struct mt9t031 *to_mt9t031(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct mt9t031, sd);
+}
+
static int reg_read(struct i2c_client *client, const u8 reg)
{
- s32 data = i2c_smbus_read_word_data(client, reg);
+ s32 data;
+
+ data = i2c_smbus_read_word_data(client, reg);
return data < 0 ? data : swab16(data);
}
@@ -110,8 +185,9 @@ static int reg_clear(struct i2c_client *client, const u8 reg,
return reg_write(client, reg, ret & ~data);
}
-static int set_shutter(struct i2c_client *client, const u32 data)
+static int set_shutter(struct v4l2_subdev *sd, const u32 data)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
ret = reg_write(client, MT9T031_SHUTTER_WIDTH_UPPER, data >> 16);
@@ -122,9 +198,10 @@ static int set_shutter(struct i2c_client *client, const u32 data)
return ret;
}
-static int get_shutter(struct i2c_client *client, u32 *data)
+static int get_shutter(struct v4l2_subdev *sd, u32 *data)
{
int ret;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
ret = reg_read(client, MT9T031_SHUTTER_WIDTH_UPPER);
*data = ret << 16;
@@ -136,20 +213,10 @@ static int get_shutter(struct i2c_client *client, u32 *data)
return ret < 0 ? ret : 0;
}
-static int mt9t031_init(struct soc_camera_device *icd)
+static int mt9t031_init(struct v4l2_subdev *sd, u32 val)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
int ret;
-
- if (icl->power) {
- ret = icl->power(&client->dev, 1);
- if (ret < 0) {
- dev_err(icd->vdev->parent,
- "Platform failed to power-on the camera.\n");
- return ret;
- }
- }
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
/* Disable chip output, synchronous option update */
ret = reg_write(client, MT9T031_RESET, 1);
@@ -158,99 +225,67 @@ static int mt9t031_init(struct soc_camera_device *icd)
if (ret >= 0)
ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
- if (ret < 0 && icl->power)
- icl->power(&client->dev, 0);
-
return ret >= 0 ? 0 : -EIO;
}
-static int mt9t031_release(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct soc_camera_link *icl = client->dev.platform_data;
-
- /* Disable the chip */
- reg_clear(client, MT9T031_OUTPUT_CONTROL, 2);
-
- if (icl->power)
- icl->power(&client->dev, 0);
-
- return 0;
-}
-
-static int mt9t031_start_capture(struct soc_camera_device *icd)
+static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
/* Switch to master "normal" mode */
- if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
- return -EIO;
- return 0;
-}
-
-static int mt9t031_stop_capture(struct soc_camera_device *icd)
-{
- struct i2c_client *client = to_i2c_client(icd->control);
-
- /* Stop sensor readout */
- if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
- return -EIO;
+ if (enable) {
+ if (reg_set(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
+ return -EIO;
+ } else {
+ /* Switch to master "" mode */
+ if (reg_clear(client, MT9T031_OUTPUT_CONTROL, 2) < 0)
+ return -EIO;
+ }
return 0;
}
-static int mt9t031_set_bus_param(struct soc_camera_device *icd,
- unsigned long flags)
+/* Round up minima and round down maxima */
+static void recalculate_limits(struct mt9t031 *mt9t031,
+ u16 xskip, u16 yskip)
{
- struct i2c_client *client = to_i2c_client(icd->control);
-
- /* The caller should have queried our parameters, check anyway */
- if (flags & ~MT9T031_BUS_PARAM)
- return -EINVAL;
-
- if (flags & SOCAM_PCLK_SAMPLE_FALLING)
- reg_clear(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
- else
- reg_set(client, MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
-
- return 0;
+ mt9t031->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
+ mt9t031->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
+ mt9t031->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip;
+ mt9t031->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip;
+ mt9t031->width_max = MT9T031_MAX_WIDTH / xskip;
+ mt9t031->height_max = MT9T031_MAX_HEIGHT / yskip;
}
-static unsigned long mt9t031_query_bus_param(struct soc_camera_device *icd)
+const struct v4l2_queryctrl *mt9t031_find_qctrl(u32 id)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
- struct soc_camera_link *icl = mt9t031->client->dev.platform_data;
+ int i;
- return soc_camera_apply_sensor_flags(icl, MT9T031_BUS_PARAM);
-}
-
-/* Round up minima and round down maxima */
-static void recalculate_limits(struct soc_camera_device *icd,
- u16 xskip, u16 yskip)
-{
- icd->x_min = (MT9T031_COLUMN_SKIP + xskip - 1) / xskip;
- icd->y_min = (MT9T031_ROW_SKIP + yskip - 1) / yskip;
- icd->width_min = (MT9T031_MIN_WIDTH + xskip - 1) / xskip;
- icd->height_min = (MT9T031_MIN_HEIGHT + yskip - 1) / yskip;
- icd->width_max = MT9T031_MAX_WIDTH / xskip;
- icd->height_max = MT9T031_MAX_HEIGHT / yskip;
+ for (i = 0; i < mt9t031_num_controls; i++) {
+ if (mt9t031_controls[i].id == id)
+ return &mt9t031_controls[i];
+ }
+ return NULL;
}
-static int mt9t031_set_params(struct soc_camera_device *icd,
+static int mt9t031_set_params(struct v4l2_subdev *sd,
struct v4l2_rect *rect, u16 xskip, u16 yskip)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct mt9t031 *mt9t031 = to_mt9t031(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
int ret;
u16 xbin, ybin, width, height, left, top;
const u16 hblank = MT9T031_HORIZONTAL_BLANK,
vblank = MT9T031_VERTICAL_BLANK;
/* Make sure we don't exceed sensor limits */
- if (rect->left + rect->width > icd->width_max)
- rect->left = (icd->width_max - rect->width) / 2 + icd->x_min;
+ if (rect->left + rect->width > mt9t031->width_max)
+ rect->left =
+ (mt9t031->width_max - rect->width) / 2 + mt9t031->x_min;
- if (rect->top + rect->height > icd->height_max)
- rect->top = (icd->height_max - rect->height) / 2 + icd->y_min;
+ if (rect->top + rect->height > mt9t031->height_max)
+ rect->top =
+ (mt9t031->height_max - rect->height) / 2 + mt9t031->y_min;
width = rect->width * xskip;
height = rect->height * yskip;
@@ -260,8 +295,9 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
xbin = min(xskip, (u16)3);
ybin = min(yskip, (u16)3);
- dev_dbg(&icd->dev, "xskip %u, width %u/%u, yskip %u, height %u/%u\n",
- xskip, width, rect->width, yskip, height, rect->height);
+ v4l2_dbg(1, debug, sd, "xskip %u, width %u/%u, yskip %u,"
+ "height %u/%u\n", xskip, width, rect->width, yskip,
+ height, rect->height);
/* Could just do roundup(rect->left, [xy]bin * 2); but this is cheaper */
switch (xbin) {
@@ -299,7 +335,7 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
ret = reg_write(client, MT9T031_ROW_ADDRESS_MODE,
((ybin - 1) << 4) | (yskip - 1));
}
- dev_dbg(&icd->dev, "new physical left %u, top %u\n", left, top);
+ v4l2_dbg(1, debug, sd, "new physical left %u, top %u\n", left, top);
/* The caller provides a supported format, as guaranteed by
* icd->try_fmt_cap(), soc_camera_s_crop() and soc_camera_cropcap() */
@@ -311,46 +347,41 @@ static int mt9t031_set_params(struct soc_camera_device *icd,
ret = reg_write(client, MT9T031_WINDOW_WIDTH, width - 1);
if (ret >= 0)
ret = reg_write(client, MT9T031_WINDOW_HEIGHT,
- height + icd->y_skip_top - 1);
+ height + mt9t031->y_skip_top - 1);
if (ret >= 0 && mt9t031->autoexposure) {
- ret = set_shutter(client, height + icd->y_skip_top + vblank);
+ ret = set_shutter(sd, height + mt9t031->y_skip_top + vblank);
if (ret >= 0) {
const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
const struct v4l2_queryctrl *qctrl =
- soc_camera_find_qctrl(icd->ops,
- V4L2_CID_EXPOSURE);
- icd->exposure = (shutter_max / 2 + (height +
- icd->y_skip_top + vblank - 1) *
+ mt9t031_find_qctrl(V4L2_CID_EXPOSURE);
+ mt9t031->exposure = (shutter_max / 2 + (height +
+ mt9t031->y_skip_top + vblank - 1) *
(qctrl->maximum - qctrl->minimum)) /
shutter_max + qctrl->minimum;
}
}
/* Re-enable register update, commit all changes */
- if (ret >= 0)
+ if (ret >= 0) {
ret = reg_clear(client, MT9T031_OUTPUT_CONTROL, 1);
-
+ /* update the values */
+ mt9t031->width = rect->width,
+ mt9t031->height = rect->height,
+ mt9t031->x_current = rect->left;
+ mt9t031->y_current = rect->top;
+ }
return ret < 0 ? ret : 0;
}
-static int mt9t031_set_crop(struct soc_camera_device *icd,
- struct v4l2_rect *rect)
-{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-
- /* CROP - no change in scaling, or in limits */
- return mt9t031_set_params(icd, rect, mt9t031->xskip, mt9t031->yskip);
-}
-
-static int mt9t031_set_fmt(struct soc_camera_device *icd,
+static int mt9t031_set_fmt(struct v4l2_subdev *sd,
struct v4l2_format *f)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct mt9t031 *mt9t031 = to_mt9t031(sd);
int ret;
u16 xskip, yskip;
struct v4l2_rect rect = {
- .left = icd->x_current,
- .top = icd->y_current,
+ .left = mt9t031->x_current,
+ .top = mt9t031->y_current,
.width = f->fmt.pix.width,
.height = f->fmt.pix.height,
};
@@ -369,18 +400,17 @@ static int mt9t031_set_fmt(struct soc_camera_device *icd,
if (rect.height * yskip <= MT9T031_MAX_HEIGHT)
break;
- recalculate_limits(icd, xskip, yskip);
+ recalculate_limits(mt9t031, xskip, yskip);
- ret = mt9t031_set_params(icd, &rect, xskip, yskip);
+ ret = mt9t031_set_params(sd, &rect, xskip, yskip);
if (!ret) {
mt9t031->xskip = xskip;
mt9t031->yskip = yskip;
}
-
return ret;
}
-static int mt9t031_try_fmt(struct soc_camera_device *icd,
+static int mt9t031_try_fmt(struct v4l2_subdev *sd,
struct v4l2_format *f)
{
struct v4l2_pix_format *pix = &f->fmt.pix;
@@ -396,19 +426,19 @@ static int mt9t031_try_fmt(struct soc_camera_device *icd,
pix->width &= ~0x01; /* has to be even */
pix->height &= ~0x01; /* has to be even */
-
return 0;
}
-static int mt9t031_get_chip_id(struct soc_camera_device *icd,
+static int mt9t031_get_chip_id(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ struct mt9t031 *mt9t031 = to_mt9t031(sd);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);;
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
- if (id->match.addr != mt9t031->client->addr)
+ if (id->match.addr != client->addr)
return -ENODEV;
id->ident = mt9t031->model;
@@ -418,10 +448,11 @@ static int mt9t031_get_chip_id(struct soc_camera_device *icd,
}
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int mt9t031_get_register(struct soc_camera_device *icd,
+static int mt9t031_get_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);;
+ struct mt9t031 *mt9t031 = to_mt9t031(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -437,10 +468,11 @@ static int mt9t031_get_register(struct soc_camera_device *icd,
return 0;
}
-static int mt9t031_set_register(struct soc_camera_device *icd,
+static int mt9t031_set_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = to_i2c_client(icd->control);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t031 *mt9t031 = to_mt9t031(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -455,85 +487,53 @@ static int mt9t031_set_register(struct soc_camera_device *icd,
}
#endif
-static const struct v4l2_queryctrl mt9t031_controls[] = {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Flip Vertically",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- }, {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Flip Horizontally",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
- }, {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 127,
- .step = 1,
- .default_value = 64,
- .flags = V4L2_CTRL_FLAG_SLIDER,
- }, {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure",
- .minimum = 1,
- .maximum = 255,
- .step = 1,
- .default_value = 255,
- .flags = V4L2_CTRL_FLAG_SLIDER,
- }, {
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Automatic Exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- }
-};
-static int mt9t031_video_probe(struct soc_camera_device *);
-static void mt9t031_video_remove(struct soc_camera_device *);
-static int mt9t031_get_control(struct soc_camera_device *, struct v4l2_control *);
-static int mt9t031_set_control(struct soc_camera_device *, struct v4l2_control *);
-
-static struct soc_camera_ops mt9t031_ops = {
- .owner = THIS_MODULE,
- .probe = mt9t031_video_probe,
- .remove = mt9t031_video_remove,
- .init = mt9t031_init,
- .release = mt9t031_release,
- .start_capture = mt9t031_start_capture,
- .stop_capture = mt9t031_stop_capture,
- .set_crop = mt9t031_set_crop,
- .set_fmt = mt9t031_set_fmt,
- .try_fmt = mt9t031_try_fmt,
- .set_bus_param = mt9t031_set_bus_param,
- .query_bus_param = mt9t031_query_bus_param,
- .controls = mt9t031_controls,
- .num_controls = ARRAY_SIZE(mt9t031_controls),
- .get_control = mt9t031_get_control,
- .set_control = mt9t031_set_control,
- .get_chip_id = mt9t031_get_chip_id,
+static int mt9t031_get_control(struct v4l2_subdev *, struct v4l2_control *);
+static int mt9t031_set_control(struct v4l2_subdev *, struct v4l2_control *);
+static int mt9t031_queryctrl(struct v4l2_subdev *, struct v4l2_queryctrl *);
+
+static const struct v4l2_subdev_core_ops mt9t031_core_ops = {
+ .g_chip_ident = mt9t031_get_chip_id,
+ .init = mt9t031_init,
+ .queryctrl = mt9t031_queryctrl,
+ .g_ctrl = mt9t031_get_control,
+ .s_ctrl = mt9t031_set_control,
#ifdef CONFIG_VIDEO_ADV_DEBUG
- .get_register = mt9t031_get_register,
- .set_register = mt9t031_set_register,
+ .get_register = mt9t031_get_register,
+ .set_register = mt9t031_set_register,
#endif
};
-static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static const struct v4l2_subdev_video_ops mt9t031_video_ops = {
+ .s_fmt = mt9t031_set_fmt,
+ .try_fmt = mt9t031_try_fmt,
+ .s_stream = mt9t031_s_stream,
+};
+
+static const struct v4l2_subdev_ops mt9t031_ops = {
+ .core = &mt9t031_core_ops,
+ .video = &mt9t031_video_ops,
+};
+
+static int mt9t031_queryctrl(struct v4l2_subdev *sd,
+ struct v4l2_queryctrl *qctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
+ const struct v4l2_queryctrl *temp_qctrl;
+
+ temp_qctrl = mt9t031_find_qctrl(qctrl->id);
+ if (!temp_qctrl) {
+ v4l2_err(sd, "control id %d not supported", qctrl->id);
+ return -EINVAL;
+ }
+ memcpy(qctrl, temp_qctrl, sizeof(*qctrl));
+ return 0;
+}
+
+static int mt9t031_get_control(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct mt9t031 *mt9t031 = to_mt9t031(sd);
int data;
switch (ctrl->id) {
@@ -556,17 +556,22 @@ static int mt9t031_get_control(struct soc_camera_device *icd, struct v4l2_contro
return 0;
}
-static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+static int mt9t031_set_control(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
- const struct v4l2_queryctrl *qctrl;
+ struct mt9t031 *mt9t031 = to_mt9t031(sd);
+ const struct v4l2_queryctrl *qctrl = NULL;
int data;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
- qctrl = soc_camera_find_qctrl(&mt9t031_ops, ctrl->id);
+ if (NULL == ctrl)
+ return -EINVAL;
- if (!qctrl)
+ qctrl = mt9t031_find_qctrl(ctrl->id);
+ if (!qctrl) {
+ v4l2_err(sd, "control id %d not supported", ctrl->id);
return -EINVAL;
+ }
switch (ctrl->id) {
case V4L2_CID_VFLIP:
@@ -594,7 +599,7 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
unsigned long range = qctrl->default_value - qctrl->minimum;
data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
- dev_dbg(&icd->dev, "Setting gain %d\n", data);
+ v4l2_dbg(1, debug, sd, "Setting gain %d\n", data);
data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
if (data < 0)
return -EIO;
@@ -606,40 +611,51 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
1015 + range / 2) / range + 9;
- if (gain <= 32) /* calculated gain 9..32 -> 9..32 */
+ if (gain <= 32)
+ /* calculated gain 9..32 -> 9..32 */
data = gain;
- else if (gain <= 64) /* calculated gain 33..64 -> 0x51..0x60 */
+ else if (gain <= 64)
+ /* calculated gain 33..64 -> 0x51..0x60 */
data = ((gain - 32) * 16 + 16) / 32 + 80;
else
- /* calculated gain 65..1024 -> (1..120) << 8 + 0x60 */
+ /*
+ * calculated gain 65..1024 -> (1..120) << 8 +
+ * 0x60
+ */
data = (((gain - 64 + 7) * 32) & 0xff00) | 0x60;
- dev_dbg(&icd->dev, "Setting gain from 0x%x to 0x%x\n",
- reg_read(client, MT9T031_GLOBAL_GAIN), data);
+ v4l2_dbg(1, debug, sd, "Setting gain from 0x%x to"
+ "0x%x\n",
+ reg_read(client, MT9T031_GLOBAL_GAIN), data);
+
data = reg_write(client, MT9T031_GLOBAL_GAIN, data);
if (data < 0)
return -EIO;
}
/* Success */
- icd->gain = ctrl->value;
+ mt9t031->gain = ctrl->value;
break;
case V4L2_CID_EXPOSURE:
/* mt9t031 has maximum == default */
- if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+ if (ctrl->value > qctrl->maximum ||
+ ctrl->value < qctrl->minimum)
return -EINVAL;
else {
- const unsigned long range = qctrl->maximum - qctrl->minimum;
- const u32 shutter = ((ctrl->value - qctrl->minimum) * 1048 +
- range / 2) / range + 1;
+ const unsigned long range =
+ qctrl->maximum - qctrl->minimum;
+ const u32 shutter =
+ ((ctrl->value - qctrl->minimum) * 1048 +
+ range / 2) / range + 1;
u32 old;
- get_shutter(client, &old);
- dev_dbg(&icd->dev, "Setting shutter width from %u to %u\n",
+ get_shutter(sd, &old);
+ v4l2_dbg(1, debug, sd,
+ "Setting shutter width from %u to %u\n",
old, shutter);
- if (set_shutter(client, shutter) < 0)
+ if (set_shutter(sd, shutter) < 0)
return -EIO;
- icd->exposure = ctrl->value;
+ mt9t031->exposure = ctrl->value;
mt9t031->autoexposure = 0;
}
break;
@@ -647,13 +663,15 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
if (ctrl->value) {
const u16 vblank = MT9T031_VERTICAL_BLANK;
const u32 shutter_max = MT9T031_MAX_HEIGHT + vblank;
- if (set_shutter(client, icd->height +
- icd->y_skip_top + vblank) < 0)
+ if (set_shutter(sd, mt9t031->height +
+ mt9t031->y_skip_top + vblank) < 0)
return -EIO;
- qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
- icd->exposure = (shutter_max / 2 + (icd->height +
- icd->y_skip_top + vblank - 1) *
- (qctrl->maximum - qctrl->minimum)) /
+
+ qctrl = mt9t031_find_qctrl(V4L2_CID_EXPOSURE);
+ mt9t031->exposure =
+ (shutter_max / 2 + (mt9t031->height +
+ mt9t031->y_skip_top + vblank - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
shutter_max + qctrl->minimum;
mt9t031->autoexposure = 1;
} else
@@ -665,130 +683,102 @@ static int mt9t031_set_control(struct soc_camera_device *icd, struct v4l2_contro
/* Interface active, can use i2c. If it fails, it can indeed mean, that
* this wasn't our capture interface, so, we wait for the right one */
-static int mt9t031_video_probe(struct soc_camera_device *icd)
+static int mt9t031_detect(struct i2c_client *client, int *model)
{
- struct i2c_client *client = to_i2c_client(icd->control);
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
s32 data;
- int ret;
-
- /* We must have a parent by now. And it cannot be a wrong one.
- * So this entire test is completely redundant. */
- if (!icd->dev.parent ||
- to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
- return -ENODEV;
/* Enable the chip */
data = reg_write(client, MT9T031_CHIP_ENABLE, 1);
- dev_dbg(&icd->dev, "write: %d\n", data);
+ dev_dbg(&client->dev, "write: %d\n", data);
/* Read out the chip version register */
data = reg_read(client, MT9T031_CHIP_VERSION);
switch (data) {
case 0x1621:
- mt9t031->model = V4L2_IDENT_MT9T031;
- icd->formats = mt9t031_colour_formats;
- icd->num_formats = ARRAY_SIZE(mt9t031_colour_formats);
+ *model = V4L2_IDENT_MT9T031;
break;
default:
- ret = -ENODEV;
- dev_err(&icd->dev,
+ dev_err(&client->dev,
"No MT9T031 chip detected, register read %x\n", data);
- goto ei2c;
+ return -ENODEV;
}
- dev_info(&icd->dev, "Detected a MT9T031 chip ID %x\n", data);
-
- /* Now that we know the model, we can start video */
- ret = soc_camera_video_start(icd);
- if (ret)
- goto evstart;
-
+ dev_info(&client->dev, "Detected a MT9T031 chip ID %x\n", data);
return 0;
-
-evstart:
-ei2c:
- return ret;
-}
-
-static void mt9t031_video_remove(struct soc_camera_device *icd)
-{
- struct mt9t031 *mt9t031 = container_of(icd, struct mt9t031, icd);
-
- dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9t031->client->addr,
- icd->dev.parent, icd->vdev);
- soc_camera_video_stop(icd);
}
static int mt9t031_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct mt9t031 *mt9t031;
- struct soc_camera_device *icd;
- struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
- struct soc_camera_link *icl = client->dev.platform_data;
+ struct v4l2_subdev *sd;
+ int pclk_pol;
int ret;
- if (!icl) {
- dev_err(&client->dev, "MT9T031 driver needs platform data\n");
- return -EINVAL;
- }
-
- if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
- dev_warn(&adapter->dev,
+ if (!i2c_check_functionality(client->adapter,
+ I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&client->dev,
"I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
return -EIO;
}
+ if (!client->dev.platform_data) {
+ dev_err(&client->dev, "No platform data!!\n");
+ return -ENODEV;
+ }
+
+ pclk_pol = (int)client->dev.platform_data;
+
mt9t031 = kzalloc(sizeof(struct mt9t031), GFP_KERNEL);
if (!mt9t031)
return -ENOMEM;
- mt9t031->client = client;
- i2c_set_clientdata(client, mt9t031);
-
- /* Second stage probe - when a capture adapter is there */
- icd = &mt9t031->icd;
- icd->ops = &mt9t031_ops;
- icd->control = &client->dev;
- icd->x_min = MT9T031_COLUMN_SKIP;
- icd->y_min = MT9T031_ROW_SKIP;
- icd->x_current = icd->x_min;
- icd->y_current = icd->y_min;
- icd->width_min = MT9T031_MIN_WIDTH;
- icd->width_max = MT9T031_MAX_WIDTH;
- icd->height_min = MT9T031_MIN_HEIGHT;
- icd->height_max = MT9T031_MAX_HEIGHT;
- icd->y_skip_top = 0;
- icd->iface = icl->bus_id;
- /* Simulated autoexposure. If enabled, we calculate shutter width
- * ourselves in the driver based on vertical blanking and frame width */
+ ret = mt9t031_detect(client, &mt9t031->model);
+ if (ret)
+ goto clean;
+
+ mt9t031->x_min = MT9T031_COLUMN_SKIP;
+ mt9t031->y_min = MT9T031_ROW_SKIP;
+ mt9t031->width = MT9T031_DEFAULT_WIDTH;
+ mt9t031->height = MT9T031_DEFAULT_WIDTH;
+ mt9t031->x_current = mt9t031->x_min;
+ mt9t031->y_current = mt9t031->y_min;
+ mt9t031->width_min = MT9T031_MIN_WIDTH;
+ mt9t031->width_max = MT9T031_MAX_WIDTH;
+ mt9t031->height_min = MT9T031_MIN_HEIGHT;
+ mt9t031->height_max = MT9T031_MAX_HEIGHT;
+ mt9t031->y_skip_top = 0;
mt9t031->autoexposure = 1;
-
mt9t031->xskip = 1;
mt9t031->yskip = 1;
- ret = soc_camera_device_register(icd);
- if (ret)
- goto eisdr;
+ /* Register with V4L2 layer as slave device */
+ sd = &mt9t031->sd;
+ v4l2_i2c_subdev_init(sd, client, &mt9t031_ops);
+ if (!pclk_pol)
+ reg_clear(v4l2_get_subdevdata(sd),
+ MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+ else
+ reg_set(v4l2_get_subdevdata(sd),
+ MT9T031_PIXEL_CLOCK_CONTROL, 0x8000);
+ v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
return 0;
-eisdr:
- i2c_set_clientdata(client, NULL);
+clean:
kfree(mt9t031);
return ret;
}
static int mt9t031_remove(struct i2c_client *client)
{
- struct mt9t031 *mt9t031 = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct mt9t031 *mt9t031 = to_mt9t031(sd);
- soc_camera_device_unregister(&mt9t031->icd);
- i2c_set_clientdata(client, NULL);
- kfree(mt9t031);
+ v4l2_device_unregister_subdev(sd);
+ kfree(mt9t031);
return 0;
}