[media] gscpa_m5602: Convert to the control framework

Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Hans de Goede 2013-02-19 14:57:03 -03:00 committed by Mauro Carvalho Chehab
parent 676fdd856b
commit c84e412f6f
15 changed files with 572 additions and 1713 deletions

View File

@ -136,16 +136,33 @@ struct sd {
/* A pointer to the currently connected sensor */ /* A pointer to the currently connected sensor */
const struct m5602_sensor *sensor; const struct m5602_sensor *sensor;
struct sd_desc *desc;
/* Sensor private data */
void *sensor_priv;
/* The current frame's id, used to detect frame boundaries */ /* The current frame's id, used to detect frame boundaries */
u8 frame_id; u8 frame_id;
/* The current frame count */ /* The current frame count */
u32 frame_count; u32 frame_count;
/* Camera rotation polling thread for "flipable" cams */
struct task_struct *rotation_thread;
struct { /* auto-white-bal + green/red/blue balance control cluster */
struct v4l2_ctrl *auto_white_bal;
struct v4l2_ctrl *red_bal;
struct v4l2_ctrl *blue_bal;
struct v4l2_ctrl *green_bal;
};
struct { /* autoexpo / expo cluster */
struct v4l2_ctrl *autoexpo;
struct v4l2_ctrl *expo;
};
struct { /* autogain / gain cluster */
struct v4l2_ctrl *autogain;
struct v4l2_ctrl *gain;
};
struct { /* hflip/vflip cluster */
struct v4l2_ctrl *hflip;
struct v4l2_ctrl *vflip;
};
}; };
int m5602_read_bridge( int m5602_read_bridge(

View File

@ -252,6 +252,16 @@ static int m5602_init(struct gspca_dev *gspca_dev)
return err; return err;
} }
static int m5602_init_controls(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
if (!sd->sensor->init_controls)
return 0;
return sd->sensor->init_controls(sd);
}
static int m5602_start_transfer(struct gspca_dev *gspca_dev) static int m5602_start_transfer(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
@ -336,11 +346,12 @@ static void m5602_stop_transfer(struct gspca_dev *gspca_dev)
sd->sensor->stop(sd); sd->sensor->stop(sd);
} }
/* sub-driver description, the ctrl and nctrl is filled at probe time */ /* sub-driver description */
static struct sd_desc sd_desc = { static const struct sd_desc sd_desc = {
.name = MODULE_NAME, .name = MODULE_NAME,
.config = m5602_configure, .config = m5602_configure,
.init = m5602_init, .init = m5602_init,
.init_controls = m5602_init_controls,
.start = m5602_start_transfer, .start = m5602_start_transfer,
.stopN = m5602_stop_transfer, .stopN = m5602_stop_transfer,
.pkt_scan = m5602_urb_complete .pkt_scan = m5602_urb_complete
@ -355,7 +366,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
int err; int err;
cam = &gspca_dev->cam; cam = &gspca_dev->cam;
sd->desc = &sd_desc;
if (dump_bridge) if (dump_bridge)
m5602_dump_bridge(sd); m5602_dump_bridge(sd);

View File

@ -20,22 +20,8 @@
#include "m5602_mt9m111.h" #include "m5602_mt9m111.h"
static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val); static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl);
static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val); static void mt9m111_dump_registers(struct sd *sd);
static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val);
static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val);
static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 *val);
static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
static struct v4l2_pix_format mt9m111_modes[] = { static struct v4l2_pix_format mt9m111_modes[] = {
{ {
@ -50,118 +36,26 @@ static struct v4l2_pix_format mt9m111_modes[] = {
} }
}; };
static const struct ctrl mt9m111_ctrls[] = { static const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
#define VFLIP_IDX 0 .s_ctrl = mt9m111_s_ctrl,
{
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "vertical flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = mt9m111_set_vflip,
.get = mt9m111_get_vflip
},
#define HFLIP_IDX 1
{
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "horizontal flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = mt9m111_set_hflip,
.get = mt9m111_get_hflip
},
#define GAIN_IDX 2
{
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "gain",
.minimum = 0,
.maximum = (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2,
.step = 1,
.default_value = MT9M111_DEFAULT_GAIN,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = mt9m111_set_gain,
.get = mt9m111_get_gain
},
#define AUTO_WHITE_BALANCE_IDX 3
{
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto white balance",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
.set = mt9m111_set_auto_white_balance,
.get = mt9m111_get_auto_white_balance
},
#define GREEN_BALANCE_IDX 4
{
{
.id = M5602_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "green balance",
.minimum = 0x00,
.maximum = 0x7ff,
.step = 0x1,
.default_value = MT9M111_GREEN_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = mt9m111_set_green_balance,
.get = mt9m111_get_green_balance
},
#define BLUE_BALANCE_IDX 5
{
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "blue balance",
.minimum = 0x00,
.maximum = 0x7ff,
.step = 0x1,
.default_value = MT9M111_BLUE_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = mt9m111_set_blue_balance,
.get = mt9m111_get_blue_balance
},
#define RED_BALANCE_IDX 5
{
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "red balance",
.minimum = 0x00,
.maximum = 0x7ff,
.step = 0x1,
.default_value = MT9M111_RED_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = mt9m111_set_red_balance,
.get = mt9m111_get_red_balance
},
}; };
static void mt9m111_dump_registers(struct sd *sd); static const struct v4l2_ctrl_config mt9m111_greenbal_cfg = {
.ops = &mt9m111_ctrl_ops,
.id = M5602_V4L2_CID_GREEN_BALANCE,
.name = "Green Balance",
.type = V4L2_CTRL_TYPE_INTEGER,
.min = 0,
.max = 0x7ff,
.step = 1,
.def = MT9M111_GREEN_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER,
};
int mt9m111_probe(struct sd *sd) int mt9m111_probe(struct sd *sd)
{ {
u8 data[2] = {0x00, 0x00}; u8 data[2] = {0x00, 0x00};
int i; int i;
s32 *sensor_settings;
if (force_sensor) { if (force_sensor) {
if (force_sensor == MT9M111_SENSOR) { if (force_sensor == MT9M111_SENSOR) {
@ -200,19 +94,8 @@ int mt9m111_probe(struct sd *sd)
return -ENODEV; return -ENODEV;
sensor_found: sensor_found:
sensor_settings = kmalloc(ARRAY_SIZE(mt9m111_ctrls) * sizeof(s32),
GFP_KERNEL);
if (!sensor_settings)
return -ENOMEM;
sd->gspca_dev.cam.cam_mode = mt9m111_modes; sd->gspca_dev.cam.cam_mode = mt9m111_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes); sd->gspca_dev.cam.nmodes = ARRAY_SIZE(mt9m111_modes);
sd->desc->ctrls = mt9m111_ctrls;
sd->desc->nctrls = ARRAY_SIZE(mt9m111_ctrls);
for (i = 0; i < ARRAY_SIZE(mt9m111_ctrls); i++)
sensor_settings[i] = mt9m111_ctrls[i].qctrl.default_value;
sd->sensor_priv = sensor_settings;
return 0; return 0;
} }
@ -220,7 +103,6 @@ sensor_found:
int mt9m111_init(struct sd *sd) int mt9m111_init(struct sd *sd)
{ {
int i, err = 0; int i, err = 0;
s32 *sensor_settings = sd->sensor_priv;
/* Init the sensor */ /* Init the sensor */
for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) { for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
@ -241,30 +123,45 @@ int mt9m111_init(struct sd *sd)
if (dump_sensor) if (dump_sensor)
mt9m111_dump_registers(sd); mt9m111_dump_registers(sd);
err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); return 0;
if (err < 0) }
return err;
err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); int mt9m111_init_controls(struct sd *sd)
if (err < 0) {
return err; struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
err = mt9m111_set_green_balance(&sd->gspca_dev, sd->gspca_dev.vdev.ctrl_handler = hdl;
sensor_settings[GREEN_BALANCE_IDX]); v4l2_ctrl_handler_init(hdl, 7);
if (err < 0)
return err;
err = mt9m111_set_blue_balance(&sd->gspca_dev, sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
sensor_settings[BLUE_BALANCE_IDX]); V4L2_CID_AUTO_WHITE_BALANCE,
if (err < 0) 0, 1, 1, 0);
return err; sd->green_bal = v4l2_ctrl_new_custom(hdl, &mt9m111_greenbal_cfg, NULL);
sd->red_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
V4L2_CID_RED_BALANCE, 0, 0x7ff, 1,
MT9M111_RED_GAIN_DEFAULT);
sd->blue_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
V4L2_CID_BLUE_BALANCE, 0, 0x7ff, 1,
MT9M111_BLUE_GAIN_DEFAULT);
err = mt9m111_set_red_balance(&sd->gspca_dev, v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_GAIN, 0,
sensor_settings[RED_BALANCE_IDX]); (INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 1,
if (err < 0) MT9M111_DEFAULT_GAIN);
return err;
return mt9m111_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); sd->hflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_HFLIP,
0, 1, 1, 0);
sd->vflip = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_VFLIP,
0, 1, 1, 0);
if (hdl->error) {
pr_err("Could not initialize controls\n");
return hdl->error;
}
v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
v4l2_ctrl_cluster(2, &sd->hflip);
return 0;
} }
int mt9m111_start(struct sd *sd) int mt9m111_start(struct sd *sd)
@ -272,7 +169,6 @@ int mt9m111_start(struct sd *sd)
int i, err = 0; int i, err = 0;
u8 data[2]; u8 data[2];
struct cam *cam = &sd->gspca_dev.cam; struct cam *cam = &sd->gspca_dev.cam;
s32 *sensor_settings = sd->sensor_priv;
int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1; int width = cam->cam_mode[sd->gspca_dev.curr_mode].width - 1;
int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
@ -334,25 +230,10 @@ int mt9m111_start(struct sd *sd)
switch (width) { switch (width) {
case 640: case 640:
PDEBUG(D_V4L2, "Configuring camera for VGA mode"); PDEBUG(D_V4L2, "Configuring camera for VGA mode");
data[0] = MT9M111_RMB_OVER_SIZED;
data[1] = MT9M111_RMB_ROW_SKIP_2X |
MT9M111_RMB_COLUMN_SKIP_2X |
(sensor_settings[VFLIP_IDX] << 0) |
(sensor_settings[HFLIP_IDX] << 1);
err = m5602_write_sensor(sd,
MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
break; break;
case 320: case 320:
PDEBUG(D_V4L2, "Configuring camera for QVGA mode"); PDEBUG(D_V4L2, "Configuring camera for QVGA mode");
data[0] = MT9M111_RMB_OVER_SIZED;
data[1] = MT9M111_RMB_ROW_SKIP_4X |
MT9M111_RMB_COLUMN_SKIP_4X |
(sensor_settings[VFLIP_IDX] << 0) |
(sensor_settings[HFLIP_IDX] << 1);
err = m5602_write_sensor(sd,
MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
break; break;
} }
return err; return err;
@ -361,105 +242,46 @@ int mt9m111_start(struct sd *sd)
void mt9m111_disconnect(struct sd *sd) void mt9m111_disconnect(struct sd *sd)
{ {
sd->sensor = NULL; sd->sensor = NULL;
kfree(sd->sensor_priv);
} }
static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
return 0;
}
static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 data[2] = {0x00, 0x00}; u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv; int hflip;
int vflip;
PDEBUG(D_V4L2, "Set vertical flip to %d", val); PDEBUG(D_V4L2, "Set hvflip to %d %d", sd->hflip->val, sd->vflip->val);
sensor_settings[VFLIP_IDX] = val;
/* The mt9m111 is flipped by default */ /* The mt9m111 is flipped by default */
val = !val; hflip = !sd->hflip->val;
vflip = !sd->vflip->val;
/* Set the correct page map */ /* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0) if (err < 0)
return err; return err;
err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2); data[0] = MT9M111_RMB_OVER_SIZED;
if (err < 0) if (gspca_dev->width == 640) {
return err; data[1] = MT9M111_RMB_ROW_SKIP_2X |
MT9M111_RMB_COLUMN_SKIP_2X |
data[1] = (data[1] & 0xfe) | val; (hflip << 1) | vflip;
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, } else {
data, 2); data[1] = MT9M111_RMB_ROW_SKIP_4X |
return err; MT9M111_RMB_COLUMN_SKIP_4X |
} (hflip << 1) | vflip;
}
static int mt9m111_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
return 0;
}
static int mt9m111_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
sensor_settings[HFLIP_IDX] = val;
/* The mt9m111 is flipped by default */
val = !val;
/* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
if (err < 0)
return err;
err = m5602_read_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, data, 2);
if (err < 0)
return err;
data[1] = (data[1] & 0xfd) | ((val << 1) & 0x02);
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B, err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
data, 2); data, 2);
return err; return err;
} }
static int mt9m111_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read gain %d", *val);
return 0;
}
static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev, static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val) __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
int err; int err;
u8 data[2]; u8 data[2];
@ -467,7 +289,6 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
if (err < 0) if (err < 0)
return err; return err;
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1)); data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2); err = m5602_write_sensor(sd, MT9M111_CP_OPERATING_MODE_CTL, data, 2);
@ -476,24 +297,11 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
return err; return err;
} }
static int mt9m111_get_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 *val) {
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
PDEBUG(D_V4L2, "Read auto white balance %d", *val);
return 0;
}
static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val) static int mt9m111_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err, tmp; int err, tmp;
u8 data[2] = {0x00, 0x00}; u8 data[2] = {0x00, 0x00};
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
sensor_settings[GAIN_IDX] = val;
/* Set the correct page map */ /* Set the correct page map */
err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2); err = m5602_write_sensor(sd, MT9M111_PAGE_MAP, data, 2);
@ -532,9 +340,7 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
int err; int err;
u8 data[2]; u8 data[2];
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
sensor_settings[GREEN_BALANCE_IDX] = val;
data[1] = (val & 0xff); data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8; data[0] = (val & 0xff00) >> 8;
@ -548,23 +354,11 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
data, 2); data, 2);
} }
static int mt9m111_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[GREEN_BALANCE_IDX];
PDEBUG(D_V4L2, "Read green balance %d", *val);
return 0;
}
static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{ {
u8 data[2]; u8 data[2];
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
sensor_settings[BLUE_BALANCE_IDX] = val;
data[1] = (val & 0xff); data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8; data[0] = (val & 0xff00) >> 8;
@ -574,23 +368,11 @@ static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
data, 2); data, 2);
} }
static int mt9m111_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[BLUE_BALANCE_IDX];
PDEBUG(D_V4L2, "Read blue balance %d", *val);
return 0;
}
static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{ {
u8 data[2]; u8 data[2];
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
sensor_settings[RED_BALANCE_IDX] = val;
data[1] = (val & 0xff); data[1] = (val & 0xff);
data[0] = (val & 0xff00) >> 8; data[0] = (val & 0xff00) >> 8;
@ -600,14 +382,40 @@ static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
data, 2); data, 2);
} }
static int mt9m111_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val) static int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl)
{ {
struct gspca_dev *gspca_dev =
container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv; int err;
*val = sensor_settings[RED_BALANCE_IDX]; if (!gspca_dev->streaming)
PDEBUG(D_V4L2, "Read red balance %d", *val); return 0;
return 0;
switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE:
err = mt9m111_set_auto_white_balance(gspca_dev, ctrl->val);
if (err || ctrl->val)
return err;
err = mt9m111_set_green_balance(gspca_dev, sd->green_bal->val);
if (err)
return err;
err = mt9m111_set_red_balance(gspca_dev, sd->red_bal->val);
if (err)
return err;
err = mt9m111_set_blue_balance(gspca_dev, sd->blue_bal->val);
break;
case V4L2_CID_GAIN:
err = mt9m111_set_gain(gspca_dev, ctrl->val);
break;
case V4L2_CID_HFLIP:
err = mt9m111_set_hvflip(gspca_dev);
break;
default:
return -EINVAL;
}
return err;
} }
static void mt9m111_dump_registers(struct sd *sd) static void mt9m111_dump_registers(struct sd *sd)

View File

@ -110,6 +110,7 @@ extern bool dump_sensor;
int mt9m111_probe(struct sd *sd); int mt9m111_probe(struct sd *sd);
int mt9m111_init(struct sd *sd); int mt9m111_init(struct sd *sd);
int mt9m111_init_controls(struct sd *sd);
int mt9m111_start(struct sd *sd); int mt9m111_start(struct sd *sd);
void mt9m111_disconnect(struct sd *sd); void mt9m111_disconnect(struct sd *sd);
@ -121,6 +122,7 @@ static const struct m5602_sensor mt9m111 = {
.probe = mt9m111_probe, .probe = mt9m111_probe,
.init = mt9m111_init, .init = mt9m111_init,
.init_controls = mt9m111_init_controls,
.disconnect = mt9m111_disconnect, .disconnect = mt9m111_disconnect,
.start = mt9m111_start, .start = mt9m111_start,
}; };

View File

@ -20,111 +20,8 @@
#include "m5602_ov7660.h" #include "m5602_ov7660.h"
static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val); static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl);
static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val); static void ov7660_dump_registers(struct sd *sd);
static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 *val);
static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val);
static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
static const struct ctrl ov7660_ctrls[] = {
#define GAIN_IDX 1
{
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "gain",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
.default_value = OV7660_DEFAULT_GAIN,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = ov7660_set_gain,
.get = ov7660_get_gain
},
#define BLUE_BALANCE_IDX 2
#define RED_BALANCE_IDX 3
#define AUTO_WHITE_BALANCE_IDX 4
{
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto white balance",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1
},
.set = ov7660_set_auto_white_balance,
.get = ov7660_get_auto_white_balance
},
#define AUTO_GAIN_CTRL_IDX 5
{
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto gain control",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1
},
.set = ov7660_set_auto_gain,
.get = ov7660_get_auto_gain
},
#define AUTO_EXPOSURE_IDX 6
{
{
.id = V4L2_CID_EXPOSURE_AUTO,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto exposure",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1
},
.set = ov7660_set_auto_exposure,
.get = ov7660_get_auto_exposure
},
#define HFLIP_IDX 7
{
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "horizontal flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = ov7660_set_hflip,
.get = ov7660_get_hflip
},
#define VFLIP_IDX 8
{
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "vertical flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = ov7660_set_vflip,
.get = ov7660_get_vflip
},
};
static struct v4l2_pix_format ov7660_modes[] = { static struct v4l2_pix_format ov7660_modes[] = {
{ {
@ -140,15 +37,15 @@ static struct v4l2_pix_format ov7660_modes[] = {
} }
}; };
static void ov7660_dump_registers(struct sd *sd); static const struct v4l2_ctrl_ops ov7660_ctrl_ops = {
.s_ctrl = ov7660_s_ctrl,
};
int ov7660_probe(struct sd *sd) int ov7660_probe(struct sd *sd)
{ {
int err = 0, i; int err = 0, i;
u8 prod_id = 0, ver_id = 0; u8 prod_id = 0, ver_id = 0;
s32 *sensor_settings;
if (force_sensor) { if (force_sensor) {
if (force_sensor == OV7660_SENSOR) { if (force_sensor == OV7660_SENSOR) {
pr_info("Forcing an %s sensor\n", ov7660.name); pr_info("Forcing an %s sensor\n", ov7660.name);
@ -191,19 +88,8 @@ int ov7660_probe(struct sd *sd)
return -ENODEV; return -ENODEV;
sensor_found: sensor_found:
sensor_settings = kmalloc(
ARRAY_SIZE(ov7660_ctrls) * sizeof(s32), GFP_KERNEL);
if (!sensor_settings)
return -ENOMEM;
sd->gspca_dev.cam.cam_mode = ov7660_modes; sd->gspca_dev.cam.cam_mode = ov7660_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes); sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov7660_modes);
sd->desc->ctrls = ov7660_ctrls;
sd->desc->nctrls = ARRAY_SIZE(ov7660_ctrls);
for (i = 0; i < ARRAY_SIZE(ov7660_ctrls); i++)
sensor_settings[i] = ov7660_ctrls[i].qctrl.default_value;
sd->sensor_priv = sensor_settings;
return 0; return 0;
} }
@ -211,7 +97,6 @@ sensor_found:
int ov7660_init(struct sd *sd) int ov7660_init(struct sd *sd)
{ {
int i, err = 0; int i, err = 0;
s32 *sensor_settings = sd->sensor_priv;
/* Init the sensor */ /* Init the sensor */
for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) { for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
@ -231,33 +116,40 @@ int ov7660_init(struct sd *sd)
if (dump_sensor) if (dump_sensor)
ov7660_dump_registers(sd); ov7660_dump_registers(sd);
err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); return 0;
if (err < 0) }
return err;
err = ov7660_set_auto_white_balance(&sd->gspca_dev, int ov7660_init_controls(struct sd *sd)
sensor_settings[AUTO_WHITE_BALANCE_IDX]); {
if (err < 0) struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
return err;
err = ov7660_set_auto_gain(&sd->gspca_dev, sd->gspca_dev.vdev.ctrl_handler = hdl;
sensor_settings[AUTO_GAIN_CTRL_IDX]); v4l2_ctrl_handler_init(hdl, 6);
if (err < 0)
return err;
err = ov7660_set_auto_exposure(&sd->gspca_dev, v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
sensor_settings[AUTO_EXPOSURE_IDX]); 0, 1, 1, 1);
if (err < 0) v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops,
return err; V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
err = ov7660_set_hflip(&sd->gspca_dev,
sensor_settings[HFLIP_IDX]);
if (err < 0)
return err;
err = ov7660_set_vflip(&sd->gspca_dev, sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops,
sensor_settings[VFLIP_IDX]); V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
sd->gain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_GAIN, 0,
255, 1, OV7660_DEFAULT_GAIN);
return err; sd->hflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_HFLIP,
0, 1, 1, 0);
sd->vflip = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_VFLIP,
0, 1, 1, 0);
if (hdl->error) {
pr_err("Could not initialize controls\n");
return hdl->error;
}
v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
v4l2_ctrl_cluster(2, &sd->hflip);
return 0;
} }
int ov7660_start(struct sd *sd) int ov7660_start(struct sd *sd)
@ -275,56 +167,29 @@ void ov7660_disconnect(struct sd *sd)
ov7660_stop(sd); ov7660_stop(sd);
sd->sensor = NULL; sd->sensor = NULL;
kfree(sd->sensor_priv);
}
static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read gain %d", *val);
return 0;
} }
static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val) static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data = val;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Setting gain to %d", val); PDEBUG(D_V4L2, "Setting gain to %d", val);
sensor_settings[GAIN_IDX] = val;
err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1); err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
return err; return err;
} }
static int ov7660_get_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
return 0;
}
static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev, static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val) __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto white balance to %d", val); PDEBUG(D_V4L2, "Set auto white balance to %d", val);
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
@ -335,26 +200,14 @@ static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
return err; return err;
} }
static int ov7660_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_GAIN_CTRL_IDX];
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
return 0;
}
static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto gain control to %d", val); PDEBUG(D_V4L2, "Set auto gain control to %d", val);
sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
@ -364,94 +217,69 @@ static int ov7660_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
} }
static int ov7660_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_EXPOSURE_IDX];
PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
return 0;
}
static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev, static int ov7660_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val) __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto exposure control to %d", val); PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1); err = m5602_read_sensor(sd, OV7660_COM8, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1); return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
} }
static int ov7660_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) static int ov7660_set_hvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
return 0;
}
static int ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set horizontal flip to %d", val); PDEBUG(D_V4L2, "Set hvflip to %d, %d", sd->hflip->val, sd->vflip->val);
sensor_settings[HFLIP_IDX] = val; i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4);
i2c_data = ((val & 0x01) << 5) |
(sensor_settings[VFLIP_IDX] << 4);
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
return err; return err;
} }
static int ov7660_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) static int ov7660_s_ctrl(struct v4l2_ctrl *ctrl)
{ {
struct gspca_dev *gspca_dev =
container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
return 0;
}
static int ov7660_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err; int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set vertical flip to %d", val); if (!gspca_dev->streaming)
sensor_settings[VFLIP_IDX] = val; return 0;
i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); switch (ctrl->id) {
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1); case V4L2_CID_AUTO_WHITE_BALANCE:
if (err < 0) err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val);
return err; break;
case V4L2_CID_EXPOSURE_AUTO:
/* When vflip is toggled we need to readjust the bridge hsync/vsync */ err = ov7660_set_auto_exposure(gspca_dev, ctrl->val);
if (gspca_dev->streaming) break;
err = ov7660_start(sd); case V4L2_CID_AUTOGAIN:
err = ov7660_set_auto_gain(gspca_dev, ctrl->val);
if (err || ctrl->val)
return err;
err = ov7660_set_gain(gspca_dev, sd->gain->val);
break;
case V4L2_CID_HFLIP:
err = ov7660_set_hvflip(gspca_dev);
break;
default:
return -EINVAL;
}
return err; return err;
} }

View File

@ -90,6 +90,8 @@ extern bool dump_sensor;
int ov7660_probe(struct sd *sd); int ov7660_probe(struct sd *sd);
int ov7660_init(struct sd *sd); int ov7660_init(struct sd *sd);
int ov7660_init(struct sd *sd);
int ov7660_init_controls(struct sd *sd);
int ov7660_start(struct sd *sd); int ov7660_start(struct sd *sd);
int ov7660_stop(struct sd *sd); int ov7660_stop(struct sd *sd);
void ov7660_disconnect(struct sd *sd); void ov7660_disconnect(struct sd *sd);
@ -100,6 +102,7 @@ static const struct m5602_sensor ov7660 = {
.i2c_regW = 1, .i2c_regW = 1,
.probe = ov7660_probe, .probe = ov7660_probe,
.init = ov7660_init, .init = ov7660_init,
.init_controls = ov7660_init_controls,
.start = ov7660_start, .start = ov7660_start,
.stop = ov7660_stop, .stop = ov7660_stop,
.disconnect = ov7660_disconnect, .disconnect = ov7660_disconnect,

View File

@ -20,26 +20,8 @@
#include "m5602_ov9650.h" #include "m5602_ov9650.h"
static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val); static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl);
static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); static void ov9650_dump_registers(struct sd *sd);
static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val);
static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 *val);
static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val);
static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val);
static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val);
static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, __s32 val);
/* Vertically and horizontally flips the image if matched, needed for machines /* Vertically and horizontally flips the image if matched, needed for machines
where the sensor is mounted upside down */ where the sensor is mounted upside down */
@ -113,140 +95,6 @@ static
{} {}
}; };
static const struct ctrl ov9650_ctrls[] = {
#define EXPOSURE_IDX 0
{
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "exposure",
.minimum = 0x00,
.maximum = 0x1ff,
.step = 0x4,
.default_value = EXPOSURE_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = ov9650_set_exposure,
.get = ov9650_get_exposure
},
#define GAIN_IDX 1
{
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "gain",
.minimum = 0x00,
.maximum = 0x3ff,
.step = 0x1,
.default_value = GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = ov9650_set_gain,
.get = ov9650_get_gain
},
#define RED_BALANCE_IDX 2
{
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "red balance",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
.default_value = RED_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = ov9650_set_red_balance,
.get = ov9650_get_red_balance
},
#define BLUE_BALANCE_IDX 3
{
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "blue balance",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
.default_value = BLUE_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = ov9650_set_blue_balance,
.get = ov9650_get_blue_balance
},
#define HFLIP_IDX 4
{
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "horizontal flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = ov9650_set_hflip,
.get = ov9650_get_hflip
},
#define VFLIP_IDX 5
{
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "vertical flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = ov9650_set_vflip,
.get = ov9650_get_vflip
},
#define AUTO_WHITE_BALANCE_IDX 6
{
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto white balance",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1
},
.set = ov9650_set_auto_white_balance,
.get = ov9650_get_auto_white_balance
},
#define AUTO_GAIN_CTRL_IDX 7
{
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto gain control",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1
},
.set = ov9650_set_auto_gain,
.get = ov9650_get_auto_gain
},
#define AUTO_EXPOSURE_IDX 8
{
{
.id = V4L2_CID_EXPOSURE_AUTO,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto exposure",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1
},
.set = ov9650_set_auto_exposure,
.get = ov9650_get_auto_exposure
}
};
static struct v4l2_pix_format ov9650_modes[] = { static struct v4l2_pix_format ov9650_modes[] = {
{ {
176, 176,
@ -291,13 +139,14 @@ static struct v4l2_pix_format ov9650_modes[] = {
} }
}; };
static void ov9650_dump_registers(struct sd *sd); static const struct v4l2_ctrl_ops ov9650_ctrl_ops = {
.s_ctrl = ov9650_s_ctrl,
};
int ov9650_probe(struct sd *sd) int ov9650_probe(struct sd *sd)
{ {
int err = 0; int err = 0;
u8 prod_id = 0, ver_id = 0, i; u8 prod_id = 0, ver_id = 0, i;
s32 *sensor_settings;
if (force_sensor) { if (force_sensor) {
if (force_sensor == OV9650_SENSOR) { if (force_sensor == OV9650_SENSOR) {
@ -338,19 +187,9 @@ int ov9650_probe(struct sd *sd)
return -ENODEV; return -ENODEV;
sensor_found: sensor_found:
sensor_settings = kmalloc(
ARRAY_SIZE(ov9650_ctrls) * sizeof(s32), GFP_KERNEL);
if (!sensor_settings)
return -ENOMEM;
sd->gspca_dev.cam.cam_mode = ov9650_modes; sd->gspca_dev.cam.cam_mode = ov9650_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes); sd->gspca_dev.cam.nmodes = ARRAY_SIZE(ov9650_modes);
sd->desc->ctrls = ov9650_ctrls;
sd->desc->nctrls = ARRAY_SIZE(ov9650_ctrls);
for (i = 0; i < ARRAY_SIZE(ov9650_ctrls); i++)
sensor_settings[i] = ov9650_ctrls[i].qctrl.default_value;
sd->sensor_priv = sensor_settings;
return 0; return 0;
} }
@ -358,7 +197,6 @@ int ov9650_init(struct sd *sd)
{ {
int i, err = 0; int i, err = 0;
u8 data; u8 data;
s32 *sensor_settings = sd->sensor_priv;
if (dump_sensor) if (dump_sensor)
ov9650_dump_registers(sd); ov9650_dump_registers(sd);
@ -372,46 +210,52 @@ int ov9650_init(struct sd *sd)
err = m5602_write_bridge(sd, init_ov9650[i][1], data); err = m5602_write_bridge(sd, init_ov9650[i][1], data);
} }
err = ov9650_set_exposure(&sd->gspca_dev, return 0;
sensor_settings[EXPOSURE_IDX]); }
if (err < 0)
return err;
err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); int ov9650_init_controls(struct sd *sd)
if (err < 0) {
return err; struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
err = ov9650_set_red_balance(&sd->gspca_dev, sd->gspca_dev.vdev.ctrl_handler = hdl;
sensor_settings[RED_BALANCE_IDX]); v4l2_ctrl_handler_init(hdl, 9);
if (err < 0)
return err;
err = ov9650_set_blue_balance(&sd->gspca_dev, sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
sensor_settings[BLUE_BALANCE_IDX]); V4L2_CID_AUTO_WHITE_BALANCE,
if (err < 0) 0, 1, 1, 1);
return err; sd->red_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
V4L2_CID_RED_BALANCE, 0, 255, 1,
RED_GAIN_DEFAULT);
sd->blue_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
V4L2_CID_BLUE_BALANCE, 0, 255, 1,
BLUE_GAIN_DEFAULT);
err = ov9650_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &ov9650_ctrl_ops,
if (err < 0) V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
return err; sd->expo = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_EXPOSURE,
0, 0x1ff, 4, EXPOSURE_DEFAULT);
err = ov9650_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); sd->autogain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
if (err < 0) V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
return err; sd->gain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_GAIN, 0,
0x3ff, 1, GAIN_DEFAULT);
err = ov9650_set_auto_exposure(&sd->gspca_dev, sd->hflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_HFLIP,
sensor_settings[AUTO_EXPOSURE_IDX]); 0, 1, 1, 0);
if (err < 0) sd->vflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_VFLIP,
return err; 0, 1, 1, 0);
err = ov9650_set_auto_white_balance(&sd->gspca_dev, if (hdl->error) {
sensor_settings[AUTO_WHITE_BALANCE_IDX]); pr_err("Could not initialize controls\n");
if (err < 0) return hdl->error;
return err; }
err = ov9650_set_auto_gain(&sd->gspca_dev, v4l2_ctrl_auto_cluster(3, &sd->auto_white_bal, 0, false);
sensor_settings[AUTO_GAIN_CTRL_IDX]); v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
return err; v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
v4l2_ctrl_cluster(2, &sd->hflip);
return 0;
} }
int ov9650_start(struct sd *sd) int ov9650_start(struct sd *sd)
@ -419,7 +263,6 @@ int ov9650_start(struct sd *sd)
u8 data; u8 data;
int i, err = 0; int i, err = 0;
struct cam *cam = &sd->gspca_dev.cam; struct cam *cam = &sd->gspca_dev.cam;
s32 *sensor_settings = sd->sensor_priv;
int width = cam->cam_mode[sd->gspca_dev.curr_mode].width; int width = cam->cam_mode[sd->gspca_dev.curr_mode].width;
int height = cam->cam_mode[sd->gspca_dev.curr_mode].height; int height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
@ -427,9 +270,9 @@ int ov9650_start(struct sd *sd)
int hor_offs = OV9650_LEFT_OFFSET; int hor_offs = OV9650_LEFT_OFFSET;
if ((!dmi_check_system(ov9650_flip_dmi_table) && if ((!dmi_check_system(ov9650_flip_dmi_table) &&
sensor_settings[VFLIP_IDX]) || sd->vflip->val) ||
(dmi_check_system(ov9650_flip_dmi_table) && (dmi_check_system(ov9650_flip_dmi_table) &&
!sensor_settings[VFLIP_IDX])) !sd->vflip->val))
ver_offs--; ver_offs--;
if (width <= 320) if (width <= 320)
@ -553,29 +396,16 @@ void ov9650_disconnect(struct sd *sd)
ov9650_stop(sd); ov9650_stop(sd);
sd->sensor = NULL; sd->sensor = NULL;
kfree(sd->sensor_priv);
}
static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[EXPOSURE_IDX];
PDEBUG(D_V4L2, "Read exposure %d", *val);
return 0;
} }
static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val) static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
PDEBUG(D_V4L2, "Set exposure to %d", val); PDEBUG(D_V4L2, "Set exposure to %d", val);
sensor_settings[EXPOSURE_IDX] = val;
/* The 6 MSBs */ /* The 6 MSBs */
i2c_data = (val >> 10) & 0x3f; i2c_data = (val >> 10) & 0x3f;
err = m5602_write_sensor(sd, OV9650_AECHM, err = m5602_write_sensor(sd, OV9650_AECHM,
@ -596,27 +426,14 @@ static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int ov9650_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read gain %d", *val);
return 0;
}
static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val) static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Setting gain to %d", val); PDEBUG(D_V4L2, "Setting gain to %d", val);
sensor_settings[GAIN_IDX] = val;
/* The 2 MSB */ /* The 2 MSB */
/* Read the OV9650_VREF register first to avoid /* Read the OV9650_VREF register first to avoid
corrupting the VREF high and low bits */ corrupting the VREF high and low bits */
@ -637,117 +454,46 @@ static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int ov9650_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[RED_BALANCE_IDX];
PDEBUG(D_V4L2, "Read red gain %d", *val);
return 0;
}
static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) static int ov9650_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set red gain to %d", val); PDEBUG(D_V4L2, "Set red gain to %d", val);
sensor_settings[RED_BALANCE_IDX] = val;
i2c_data = val & 0xff; i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1); err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
return err; return err;
} }
static int ov9650_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[BLUE_BALANCE_IDX];
PDEBUG(D_V4L2, "Read blue gain %d", *val);
return 0;
}
static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) static int ov9650_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set blue gain to %d", val); PDEBUG(D_V4L2, "Set blue gain to %d", val);
sensor_settings[BLUE_BALANCE_IDX] = val;
i2c_data = val & 0xff; i2c_data = val & 0xff;
err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1); err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
return err; return err;
} }
static int ov9650_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) static int ov9650_set_hvflip(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
return 0;
}
static int ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv; int hflip = sd->hflip->val;
int vflip = sd->vflip->val;
PDEBUG(D_V4L2, "Set horizontal flip to %d", val); PDEBUG(D_V4L2, "Set hvflip to %d %d", hflip, vflip);
sensor_settings[HFLIP_IDX] = val;
if (!dmi_check_system(ov9650_flip_dmi_table))
i2c_data = ((val & 0x01) << 5) |
(sensor_settings[VFLIP_IDX] << 4);
else
i2c_data = ((val & 0x01) << 5) |
(!sensor_settings[VFLIP_IDX] << 4);
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
return err;
}
static int ov9650_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
return 0;
}
static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
sensor_settings[VFLIP_IDX] = val;
if (dmi_check_system(ov9650_flip_dmi_table)) if (dmi_check_system(ov9650_flip_dmi_table))
val = !val; vflip = !vflip;
i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5); i2c_data = (hflip << 5) | (vflip << 4);
err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1); err = m5602_write_sensor(sd, OV9650_MVFP, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
@ -759,57 +505,34 @@ static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int ov9650_get_auto_exposure(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_EXPOSURE_IDX];
PDEBUG(D_V4L2, "Read auto exposure control %d", *val);
return 0;
}
static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev, static int ov9650_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val) __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto exposure control to %d", val); PDEBUG(D_V4L2, "Set auto exposure control to %d", val);
sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0)); i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
} }
static int ov9650_get_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
return 0;
}
static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev, static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val) __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto white balance to %d", val); PDEBUG(D_V4L2, "Set auto white balance to %d", val);
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
@ -820,26 +543,14 @@ static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
return err; return err;
} }
static int ov9650_get_auto_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_GAIN_CTRL_IDX];
PDEBUG(D_V4L2, "Read auto gain control %d", *val);
return 0;
}
static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val) static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 i2c_data; u8 i2c_data;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
PDEBUG(D_V4L2, "Set auto gain control to %d", val); PDEBUG(D_V4L2, "Set auto gain control to %d", val);
sensor_settings[AUTO_GAIN_CTRL_IDX] = val;
err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1); err = m5602_read_sensor(sd, OV9650_COM8, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
@ -849,6 +560,48 @@ static int ov9650_set_auto_gain(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1); return m5602_write_sensor(sd, OV9650_COM8, &i2c_data, 1);
} }
static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct gspca_dev *gspca_dev =
container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
struct sd *sd = (struct sd *) gspca_dev;
int err;
if (!gspca_dev->streaming)
return 0;
switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE:
err = ov9650_set_auto_white_balance(gspca_dev, ctrl->val);
if (err || ctrl->val)
return err;
err = ov9650_set_red_balance(gspca_dev, sd->red_bal->val);
if (err)
return err;
err = ov9650_set_blue_balance(gspca_dev, sd->blue_bal->val);
break;
case V4L2_CID_EXPOSURE_AUTO:
err = ov9650_set_auto_exposure(gspca_dev, ctrl->val);
if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
return err;
err = ov9650_set_exposure(gspca_dev, sd->expo->val);
break;
case V4L2_CID_AUTOGAIN:
err = ov9650_set_auto_gain(gspca_dev, ctrl->val);
if (err || ctrl->val)
return err;
err = ov9650_set_gain(gspca_dev, sd->gain->val);
break;
case V4L2_CID_HFLIP:
err = ov9650_set_hvflip(gspca_dev);
break;
default:
return -EINVAL;
}
return err;
}
static void ov9650_dump_registers(struct sd *sd) static void ov9650_dump_registers(struct sd *sd)
{ {
int address; int address;

View File

@ -139,6 +139,7 @@ extern bool dump_sensor;
int ov9650_probe(struct sd *sd); int ov9650_probe(struct sd *sd);
int ov9650_init(struct sd *sd); int ov9650_init(struct sd *sd);
int ov9650_init_controls(struct sd *sd);
int ov9650_start(struct sd *sd); int ov9650_start(struct sd *sd);
int ov9650_stop(struct sd *sd); int ov9650_stop(struct sd *sd);
void ov9650_disconnect(struct sd *sd); void ov9650_disconnect(struct sd *sd);
@ -149,6 +150,7 @@ static const struct m5602_sensor ov9650 = {
.i2c_regW = 1, .i2c_regW = 1,
.probe = ov9650_probe, .probe = ov9650_probe,
.init = ov9650_init, .init = ov9650_init,
.init_controls = ov9650_init_controls,
.start = ov9650_start, .start = ov9650_start,
.stop = ov9650_stop, .stop = ov9650_stop,
.disconnect = ov9650_disconnect, .disconnect = ov9650_disconnect,

View File

@ -20,28 +20,8 @@
#include "m5602_po1030.h" #include "m5602_po1030.h"
static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); static int po1030_s_ctrl(struct v4l2_ctrl *ctrl);
static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val); static void po1030_dump_registers(struct sd *sd);
static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val);
static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val);
static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val);
static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val);
static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val);
static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val);
static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 *val);
static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val);
static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
__s32 *val);
static struct v4l2_pix_format po1030_modes[] = { static struct v4l2_pix_format po1030_modes[] = {
{ {
@ -56,146 +36,25 @@ static struct v4l2_pix_format po1030_modes[] = {
} }
}; };
static const struct ctrl po1030_ctrls[] = { static const struct v4l2_ctrl_ops po1030_ctrl_ops = {
#define GAIN_IDX 0 .s_ctrl = po1030_s_ctrl,
{
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "gain",
.minimum = 0x00,
.maximum = 0x4f,
.step = 0x1,
.default_value = PO1030_GLOBAL_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_gain,
.get = po1030_get_gain
},
#define EXPOSURE_IDX 1
{
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "exposure",
.minimum = 0x00,
.maximum = 0x02ff,
.step = 0x1,
.default_value = PO1030_EXPOSURE_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_exposure,
.get = po1030_get_exposure
},
#define RED_BALANCE_IDX 2
{
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "red balance",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
.default_value = PO1030_RED_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_red_balance,
.get = po1030_get_red_balance
},
#define BLUE_BALANCE_IDX 3
{
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "blue balance",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
.default_value = PO1030_BLUE_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_blue_balance,
.get = po1030_get_blue_balance
},
#define HFLIP_IDX 4
{
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "horizontal flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
.set = po1030_set_hflip,
.get = po1030_get_hflip
},
#define VFLIP_IDX 5
{
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "vertical flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
.set = po1030_set_vflip,
.get = po1030_get_vflip
},
#define AUTO_WHITE_BALANCE_IDX 6
{
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto white balance",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
.set = po1030_set_auto_white_balance,
.get = po1030_get_auto_white_balance
},
#define AUTO_EXPOSURE_IDX 7
{
{
.id = V4L2_CID_EXPOSURE_AUTO,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "auto exposure",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0,
},
.set = po1030_set_auto_exposure,
.get = po1030_get_auto_exposure
},
#define GREEN_BALANCE_IDX 8
{
{
.id = M5602_V4L2_CID_GREEN_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "green balance",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
.default_value = PO1030_GREEN_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_green_balance,
.get = po1030_get_green_balance
},
}; };
static void po1030_dump_registers(struct sd *sd); static const struct v4l2_ctrl_config po1030_greenbal_cfg = {
.ops = &po1030_ctrl_ops,
.id = M5602_V4L2_CID_GREEN_BALANCE,
.name = "Green Balance",
.type = V4L2_CTRL_TYPE_INTEGER,
.min = 0,
.max = 255,
.step = 1,
.def = PO1030_GREEN_GAIN_DEFAULT,
.flags = V4L2_CTRL_FLAG_SLIDER,
};
int po1030_probe(struct sd *sd) int po1030_probe(struct sd *sd)
{ {
u8 dev_id_h = 0, i; u8 dev_id_h = 0, i;
s32 *sensor_settings;
if (force_sensor) { if (force_sensor) {
if (force_sensor == PO1030_SENSOR) { if (force_sensor == PO1030_SENSOR) {
@ -229,26 +88,14 @@ int po1030_probe(struct sd *sd)
return -ENODEV; return -ENODEV;
sensor_found: sensor_found:
sensor_settings = kmalloc(
ARRAY_SIZE(po1030_ctrls) * sizeof(s32), GFP_KERNEL);
if (!sensor_settings)
return -ENOMEM;
sd->gspca_dev.cam.cam_mode = po1030_modes; sd->gspca_dev.cam.cam_mode = po1030_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes); sd->gspca_dev.cam.nmodes = ARRAY_SIZE(po1030_modes);
sd->desc->ctrls = po1030_ctrls;
sd->desc->nctrls = ARRAY_SIZE(po1030_ctrls);
for (i = 0; i < ARRAY_SIZE(po1030_ctrls); i++)
sensor_settings[i] = po1030_ctrls[i].qctrl.default_value;
sd->sensor_priv = sensor_settings;
return 0; return 0;
} }
int po1030_init(struct sd *sd) int po1030_init(struct sd *sd)
{ {
s32 *sensor_settings = sd->sensor_priv;
int i, err = 0; int i, err = 0;
/* Init the sensor */ /* Init the sensor */
@ -279,46 +126,50 @@ int po1030_init(struct sd *sd)
if (dump_sensor) if (dump_sensor)
po1030_dump_registers(sd); po1030_dump_registers(sd);
err = po1030_set_exposure(&sd->gspca_dev, return 0;
sensor_settings[EXPOSURE_IDX]); }
if (err < 0)
return err;
err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]); int po1030_init_controls(struct sd *sd)
if (err < 0) {
return err; struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]); sd->gspca_dev.vdev.ctrl_handler = hdl;
if (err < 0) v4l2_ctrl_handler_init(hdl, 9);
return err;
err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]); sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
if (err < 0) V4L2_CID_AUTO_WHITE_BALANCE,
return err; 0, 1, 1, 0);
sd->green_bal = v4l2_ctrl_new_custom(hdl, &po1030_greenbal_cfg, NULL);
sd->red_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
V4L2_CID_RED_BALANCE, 0, 255, 1,
PO1030_RED_GAIN_DEFAULT);
sd->blue_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
V4L2_CID_BLUE_BALANCE, 0, 255, 1,
PO1030_BLUE_GAIN_DEFAULT);
err = po1030_set_red_balance(&sd->gspca_dev, sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops,
sensor_settings[RED_BALANCE_IDX]); V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL);
if (err < 0) sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE,
return err; 0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT);
err = po1030_set_blue_balance(&sd->gspca_dev, sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0,
sensor_settings[BLUE_BALANCE_IDX]); 0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT);
if (err < 0)
return err;
err = po1030_set_green_balance(&sd->gspca_dev, sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP,
sensor_settings[GREEN_BALANCE_IDX]); 0, 1, 1, 0);
if (err < 0) sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP,
return err; 0, 1, 1, 0);
err = po1030_set_auto_white_balance(&sd->gspca_dev, if (hdl->error) {
sensor_settings[AUTO_WHITE_BALANCE_IDX]); pr_err("Could not initialize controls\n");
if (err < 0) return hdl->error;
return err; }
err = po1030_set_auto_exposure(&sd->gspca_dev, v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
sensor_settings[AUTO_EXPOSURE_IDX]); v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
return err; v4l2_ctrl_cluster(2, &sd->hflip);
return 0;
} }
int po1030_start(struct sd *sd) int po1030_start(struct sd *sd)
@ -448,24 +299,12 @@ int po1030_start(struct sd *sd)
return err; return err;
} }
static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[EXPOSURE_IDX];
PDEBUG(D_V4L2, "Exposure read as %d", *val);
return 0;
}
static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val) static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
sensor_settings[EXPOSURE_IDX] = val;
PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff); PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
i2c_data = ((val & 0xff00) >> 8); i2c_data = ((val & 0xff00) >> 8);
@ -486,25 +325,12 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int po1030_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read global gain %d", *val);
return 0;
}
static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val) static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
sensor_settings[GAIN_IDX] = val;
i2c_data = val & 0xff; i2c_data = val & 0xff;
PDEBUG(D_V4L2, "Set global gain to %d", i2c_data); PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_GLOBALGAIN, err = m5602_write_sensor(sd, PO1030_GLOBALGAIN,
@ -512,32 +338,19 @@ static int po1030_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int po1030_get_hflip(struct gspca_dev *gspca_dev, __s32 *val) static int po1030_set_hvflip(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read hflip %d", *val);
return 0;
}
static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
sensor_settings[HFLIP_IDX] = val; PDEBUG(D_V4L2, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val);
PDEBUG(D_V4L2, "Set hflip %d", val);
err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1); err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
i2c_data = (0x7f & i2c_data) | ((val & 0x01) << 7); i2c_data = (0x3f & i2c_data) | (sd->hflip->val << 7) |
(sd->vflip->val << 6);
err = m5602_write_sensor(sd, PO1030_CONTROL2, err = m5602_write_sensor(sd, PO1030_CONTROL2,
&i2c_data, 1); &i2c_data, 1);
@ -545,58 +358,12 @@ static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int po1030_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vflip %d", *val);
return 0;
}
static int po1030_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data;
int err;
sensor_settings[VFLIP_IDX] = val;
PDEBUG(D_V4L2, "Set vflip %d", val);
err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
if (err < 0)
return err;
i2c_data = (i2c_data & 0xbf) | ((val & 0x01) << 6);
err = m5602_write_sensor(sd, PO1030_CONTROL2,
&i2c_data, 1);
return err;
}
static int po1030_get_red_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[RED_BALANCE_IDX];
PDEBUG(D_V4L2, "Read red gain %d", *val);
return 0;
}
static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val) static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
sensor_settings[RED_BALANCE_IDX] = val;
i2c_data = val & 0xff; i2c_data = val & 0xff;
PDEBUG(D_V4L2, "Set red gain to %d", i2c_data); PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_RED_GAIN, err = m5602_write_sensor(sd, PO1030_RED_GAIN,
@ -604,26 +371,12 @@ static int po1030_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int po1030_get_blue_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[BLUE_BALANCE_IDX];
PDEBUG(D_V4L2, "Read blue gain %d", *val);
return 0;
}
static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val) static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
sensor_settings[BLUE_BALANCE_IDX] = val;
i2c_data = val & 0xff; i2c_data = val & 0xff;
PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data); PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
err = m5602_write_sensor(sd, PO1030_BLUE_GAIN, err = m5602_write_sensor(sd, PO1030_BLUE_GAIN,
@ -632,25 +385,12 @@ static int po1030_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int po1030_get_green_balance(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[GREEN_BALANCE_IDX];
PDEBUG(D_V4L2, "Read green gain %d", *val);
return 0;
}
static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val) static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
sensor_settings[GREEN_BALANCE_IDX] = val;
i2c_data = val & 0xff; i2c_data = val & 0xff;
PDEBUG(D_V4L2, "Set green gain to %d", i2c_data); PDEBUG(D_V4L2, "Set green gain to %d", i2c_data);
@ -663,28 +403,13 @@ static int po1030_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
&i2c_data, 1); &i2c_data, 1);
} }
static int po1030_get_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_WHITE_BALANCE_IDX];
PDEBUG(D_V4L2, "Auto white balancing is %d", *val);
return 0;
}
static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev, static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
__s32 val) __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
@ -695,31 +420,19 @@ static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
return err; return err;
} }
static int po1030_get_auto_exposure(struct gspca_dev *gspca_dev,
__s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[AUTO_EXPOSURE_IDX];
PDEBUG(D_V4L2, "Auto exposure is %d", *val);
return 0;
}
static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev, static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
__s32 val) __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 i2c_data; u8 i2c_data;
int err; int err;
sensor_settings[AUTO_EXPOSURE_IDX] = val;
err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
if (err < 0) if (err < 0)
return err; return err;
PDEBUG(D_V4L2, "Set auto exposure to %d", val); PDEBUG(D_V4L2, "Set auto exposure to %d", val);
val = (val == V4L2_EXPOSURE_AUTO);
i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1); i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 1);
return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1); return m5602_write_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
} }
@ -727,7 +440,48 @@ static int po1030_set_auto_exposure(struct gspca_dev *gspca_dev,
void po1030_disconnect(struct sd *sd) void po1030_disconnect(struct sd *sd)
{ {
sd->sensor = NULL; sd->sensor = NULL;
kfree(sd->sensor_priv); }
static int po1030_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct gspca_dev *gspca_dev =
container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
struct sd *sd = (struct sd *) gspca_dev;
int err;
if (!gspca_dev->streaming)
return 0;
switch (ctrl->id) {
case V4L2_CID_AUTO_WHITE_BALANCE:
err = po1030_set_auto_white_balance(gspca_dev, ctrl->val);
if (err || ctrl->val)
return err;
err = po1030_set_green_balance(gspca_dev, sd->green_bal->val);
if (err)
return err;
err = po1030_set_red_balance(gspca_dev, sd->red_bal->val);
if (err)
return err;
err = po1030_set_blue_balance(gspca_dev, sd->blue_bal->val);
break;
case V4L2_CID_EXPOSURE_AUTO:
err = po1030_set_auto_exposure(gspca_dev, ctrl->val);
if (err || ctrl->val == V4L2_EXPOSURE_AUTO)
return err;
err = po1030_set_exposure(gspca_dev, sd->expo->val);
break;
case V4L2_CID_GAIN:
err = po1030_set_gain(gspca_dev, ctrl->val);
break;
case V4L2_CID_HFLIP:
err = po1030_set_hvflip(gspca_dev);
break;
default:
return -EINVAL;
}
return err;
} }
static void po1030_dump_registers(struct sd *sd) static void po1030_dump_registers(struct sd *sd)

View File

@ -151,6 +151,7 @@ extern bool dump_sensor;
int po1030_probe(struct sd *sd); int po1030_probe(struct sd *sd);
int po1030_init(struct sd *sd); int po1030_init(struct sd *sd);
int po1030_init_controls(struct sd *sd);
int po1030_start(struct sd *sd); int po1030_start(struct sd *sd);
void po1030_disconnect(struct sd *sd); void po1030_disconnect(struct sd *sd);
@ -162,6 +163,7 @@ static const struct m5602_sensor po1030 = {
.probe = po1030_probe, .probe = po1030_probe,
.init = po1030_init, .init = po1030_init,
.init_controls = po1030_init_controls,
.start = po1030_start, .start = po1030_start,
.disconnect = po1030_disconnect, .disconnect = po1030_disconnect,
}; };

View File

@ -20,18 +20,12 @@
#include "m5602_s5k4aa.h" #include "m5602_s5k4aa.h"
static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val); static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val); static void s5k4aa_dump_registers(struct sd *sd);
static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val); static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val); .s_ctrl = s5k4aa_s_ctrl,
static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val); };
static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val);
static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val);
static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val);
static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
static static
const const
@ -147,104 +141,11 @@ static struct v4l2_pix_format s5k4aa_modes[] = {
} }
}; };
static const struct ctrl s5k4aa_ctrls[] = {
#define VFLIP_IDX 0
{
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "vertical flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = s5k4aa_set_vflip,
.get = s5k4aa_get_vflip
},
#define HFLIP_IDX 1
{
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "horizontal flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = s5k4aa_set_hflip,
.get = s5k4aa_get_hflip
},
#define GAIN_IDX 2
{
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Gain",
.minimum = 0,
.maximum = 127,
.step = 1,
.default_value = S5K4AA_DEFAULT_GAIN,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = s5k4aa_set_gain,
.get = s5k4aa_get_gain
},
#define EXPOSURE_IDX 3
{
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = 13,
.maximum = 0xfff,
.step = 1,
.default_value = 0x100,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = s5k4aa_set_exposure,
.get = s5k4aa_get_exposure
},
#define NOISE_SUPP_IDX 4
{
{
.id = V4L2_CID_PRIVATE_BASE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Noise suppression (smoothing)",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 1,
},
.set = s5k4aa_set_noise,
.get = s5k4aa_get_noise
},
#define BRIGHTNESS_IDX 5
{
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0,
.maximum = 0x1f,
.step = 1,
.default_value = S5K4AA_DEFAULT_BRIGHTNESS,
},
.set = s5k4aa_set_brightness,
.get = s5k4aa_get_brightness
},
};
static void s5k4aa_dump_registers(struct sd *sd);
int s5k4aa_probe(struct sd *sd) int s5k4aa_probe(struct sd *sd)
{ {
u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75}; const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
int i, err = 0; int i, err = 0;
s32 *sensor_settings;
if (force_sensor) { if (force_sensor) {
if (force_sensor == S5K4AA_SENSOR) { if (force_sensor == S5K4AA_SENSOR) {
@ -303,19 +204,8 @@ int s5k4aa_probe(struct sd *sd)
pr_info("Detected a s5k4aa sensor\n"); pr_info("Detected a s5k4aa sensor\n");
sensor_found: sensor_found:
sensor_settings = kmalloc(
ARRAY_SIZE(s5k4aa_ctrls) * sizeof(s32), GFP_KERNEL);
if (!sensor_settings)
return -ENOMEM;
sd->gspca_dev.cam.cam_mode = s5k4aa_modes; sd->gspca_dev.cam.cam_mode = s5k4aa_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes); sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k4aa_modes);
sd->desc->ctrls = s5k4aa_ctrls;
sd->desc->nctrls = ARRAY_SIZE(s5k4aa_ctrls);
for (i = 0; i < ARRAY_SIZE(s5k4aa_ctrls); i++)
sensor_settings[i] = s5k4aa_ctrls[i].qctrl.default_value;
sd->sensor_priv = sensor_settings;
return 0; return 0;
} }
@ -325,7 +215,6 @@ int s5k4aa_start(struct sd *sd)
int i, err = 0; int i, err = 0;
u8 data[2]; u8 data[2];
struct cam *cam = &sd->gspca_dev.cam; struct cam *cam = &sd->gspca_dev.cam;
s32 *sensor_settings = sd->sensor_priv;
switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) { switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
case 1280: case 1280:
@ -359,9 +248,6 @@ int s5k4aa_start(struct sd *sd)
return -EINVAL; return -EINVAL;
} }
} }
err = s5k4aa_set_noise(&sd->gspca_dev, 0);
if (err < 0)
return err;
break; break;
case 640: case 640:
@ -395,37 +281,12 @@ int s5k4aa_start(struct sd *sd)
return -EINVAL; return -EINVAL;
} }
} }
err = s5k4aa_set_noise(&sd->gspca_dev, 1);
if (err < 0)
return err;
break; break;
} }
if (err < 0) if (err < 0)
return err; return err;
err = s5k4aa_set_exposure(&sd->gspca_dev, return 0;
sensor_settings[EXPOSURE_IDX]);
if (err < 0)
return err;
err = s5k4aa_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
if (err < 0)
return err;
err = s5k4aa_set_brightness(&sd->gspca_dev,
sensor_settings[BRIGHTNESS_IDX]);
if (err < 0)
return err;
err = s5k4aa_set_noise(&sd->gspca_dev, sensor_settings[NOISE_SUPP_IDX]);
if (err < 0)
return err;
err = s5k4aa_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
if (err < 0)
return err;
return s5k4aa_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
} }
int s5k4aa_init(struct sd *sd) int s5k4aa_init(struct sd *sd)
@ -466,13 +327,36 @@ int s5k4aa_init(struct sd *sd)
return err; return err;
} }
static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val) int s5k4aa_init_controls(struct sd *sd)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[EXPOSURE_IDX]; sd->gspca_dev.vdev.ctrl_handler = hdl;
PDEBUG(D_V4L2, "Read exposure %d", *val); v4l2_ctrl_handler_init(hdl, 6);
v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_BRIGHTNESS,
0, 0x1f, 1, S5K4AA_DEFAULT_BRIGHTNESS);
v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_EXPOSURE,
13, 0xfff, 1, 0x100);
v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_GAIN,
0, 127, 1, S5K4AA_DEFAULT_GAIN);
v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_SHARPNESS,
0, 1, 1, 1);
sd->hflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_HFLIP,
0, 1, 1, 0);
sd->vflip = v4l2_ctrl_new_std(hdl, &s5k4aa_ctrl_ops, V4L2_CID_VFLIP,
0, 1, 1, 0);
if (hdl->error) {
pr_err("Could not initialize controls\n");
return hdl->error;
}
v4l2_ctrl_cluster(2, &sd->hflip);
return 0; return 0;
} }
@ -480,11 +364,9 @@ static int s5k4aa_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val) static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2; u8 data = S5K4AA_PAGE_MAP_2;
int err; int err;
sensor_settings[EXPOSURE_IDX] = val;
PDEBUG(D_V4L2, "Set exposure to %d", val); PDEBUG(D_V4L2, "Set exposure to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0) if (err < 0)
@ -499,27 +381,15 @@ static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int s5k4aa_get_vflip(struct gspca_dev *gspca_dev, __s32 *val) static int s5k4aa_set_hvflip(struct gspca_dev *gspca_dev)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[VFLIP_IDX];
PDEBUG(D_V4L2, "Read vertical flip %d", *val);
return 0;
}
static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2; u8 data = S5K4AA_PAGE_MAP_2;
int err; int err;
int hflip = sd->hflip->val;
int vflip = sd->vflip->val;
sensor_settings[VFLIP_IDX] = val; PDEBUG(D_V4L2, "Set hvflip %d %d", hflip, vflip);
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0) if (err < 0)
return err; return err;
@ -528,58 +398,12 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
if (err < 0) if (err < 0)
return err; return err;
if (dmi_check_system(s5k4aa_vflip_dmi_table)) if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
val = !val; hflip = !hflip;
vflip = !vflip;
}
data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7)); data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
return err;
err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
if (err < 0)
return err;
if (val)
data &= 0xfe;
else
data |= 0x01;
err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
return err;
}
static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[HFLIP_IDX];
PDEBUG(D_V4L2, "Read horizontal flip %d", *val);
return 0;
}
static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2;
int err;
sensor_settings[HFLIP_IDX] = val;
PDEBUG(D_V4L2, "Set horizontal flip to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0)
return err;
err = m5602_read_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0)
return err;
if (dmi_check_system(s5k4aa_vflip_dmi_table))
val = !val;
data = ((data & ~S5K4AA_RM_H_FLIP) | ((val & 0x01) << 6));
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1); err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
if (err < 0) if (err < 0)
return err; return err;
@ -587,33 +411,34 @@ static int s5k4aa_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); err = m5602_read_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
if (err < 0) if (err < 0)
return err; return err;
if (val) if (hflip)
data &= 0xfe; data &= 0xfe;
else else
data |= 0x01; data |= 0x01;
err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1); err = m5602_write_sensor(sd, S5K4AA_COLSTART_LO, &data, 1);
return err; if (err < 0)
} return err;
static int s5k4aa_get_gain(struct gspca_dev *gspca_dev, __s32 *val) err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
{ if (err < 0)
struct sd *sd = (struct sd *) gspca_dev; return err;
s32 *sensor_settings = sd->sensor_priv; if (vflip)
data &= 0xfe;
else
data |= 0x01;
err = m5602_write_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
if (err < 0)
return err;
*val = sensor_settings[GAIN_IDX];
PDEBUG(D_V4L2, "Read gain %d", *val);
return 0; return 0;
} }
static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val) static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2; u8 data = S5K4AA_PAGE_MAP_2;
int err; int err;
sensor_settings[GAIN_IDX] = val;
PDEBUG(D_V4L2, "Set gain to %d", val); PDEBUG(D_V4L2, "Set gain to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0) if (err < 0)
@ -625,25 +450,12 @@ static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int s5k4aa_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[BRIGHTNESS_IDX];
PDEBUG(D_V4L2, "Read brightness %d", *val);
return 0;
}
static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val) static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2; u8 data = S5K4AA_PAGE_MAP_2;
int err; int err;
sensor_settings[BRIGHTNESS_IDX] = val;
PDEBUG(D_V4L2, "Set brightness to %d", val); PDEBUG(D_V4L2, "Set brightness to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0) if (err < 0)
@ -653,25 +465,12 @@ static int s5k4aa_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1); return m5602_write_sensor(sd, S5K4AA_BRIGHTNESS, &data, 1);
} }
static int s5k4aa_get_noise(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
*val = sensor_settings[NOISE_SUPP_IDX];
PDEBUG(D_V4L2, "Read noise %d", *val);
return 0;
}
static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val) static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
{ {
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
s32 *sensor_settings = sd->sensor_priv;
u8 data = S5K4AA_PAGE_MAP_2; u8 data = S5K4AA_PAGE_MAP_2;
int err; int err;
sensor_settings[NOISE_SUPP_IDX] = val;
PDEBUG(D_V4L2, "Set noise to %d", val); PDEBUG(D_V4L2, "Set noise to %d", val);
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1); err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
if (err < 0) if (err < 0)
@ -681,10 +480,41 @@ static int s5k4aa_set_noise(struct gspca_dev *gspca_dev, __s32 val)
return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1); return m5602_write_sensor(sd, S5K4AA_NOISE_SUPP, &data, 1);
} }
static int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct gspca_dev *gspca_dev =
container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
int err;
if (!gspca_dev->streaming)
return 0;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
err = s5k4aa_set_brightness(gspca_dev, ctrl->val);
break;
case V4L2_CID_EXPOSURE:
err = s5k4aa_set_exposure(gspca_dev, ctrl->val);
break;
case V4L2_CID_GAIN:
err = s5k4aa_set_gain(gspca_dev, ctrl->val);
break;
case V4L2_CID_SHARPNESS:
err = s5k4aa_set_noise(gspca_dev, ctrl->val);
break;
case V4L2_CID_HFLIP:
err = s5k4aa_set_hvflip(gspca_dev);
break;
default:
return -EINVAL;
}
return err;
}
void s5k4aa_disconnect(struct sd *sd) void s5k4aa_disconnect(struct sd *sd)
{ {
sd->sensor = NULL; sd->sensor = NULL;
kfree(sd->sensor_priv);
} }
static void s5k4aa_dump_registers(struct sd *sd) static void s5k4aa_dump_registers(struct sd *sd)

View File

@ -69,6 +69,7 @@ extern bool dump_sensor;
int s5k4aa_probe(struct sd *sd); int s5k4aa_probe(struct sd *sd);
int s5k4aa_init(struct sd *sd); int s5k4aa_init(struct sd *sd);
int s5k4aa_init_controls(struct sd *sd);
int s5k4aa_start(struct sd *sd); int s5k4aa_start(struct sd *sd);
void s5k4aa_disconnect(struct sd *sd); void s5k4aa_disconnect(struct sd *sd);
@ -79,6 +80,7 @@ static const struct m5602_sensor s5k4aa = {
.probe = s5k4aa_probe, .probe = s5k4aa_probe,
.init = s5k4aa_init, .init = s5k4aa_init,
.init_controls = s5k4aa_init_controls,
.start = s5k4aa_start, .start = s5k4aa_start,
.disconnect = s5k4aa_disconnect, .disconnect = s5k4aa_disconnect,
}; };

View File

@ -21,16 +21,11 @@
#include <linux/kthread.h> #include <linux/kthread.h>
#include "m5602_s5k83a.h" #include "m5602_s5k83a.h"
static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val); static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val); static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val); .s_ctrl = s5k83a_s_ctrl,
static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val); };
static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);
static struct v4l2_pix_format s5k83a_modes[] = { static struct v4l2_pix_format s5k83a_modes[] = {
{ {
@ -46,83 +41,6 @@ static struct v4l2_pix_format s5k83a_modes[] = {
} }
}; };
static const struct ctrl s5k83a_ctrls[] = {
#define GAIN_IDX 0
{
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "gain",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x01,
.default_value = S5K83A_DEFAULT_GAIN,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = s5k83a_set_gain,
.get = s5k83a_get_gain
},
#define BRIGHTNESS_IDX 1
{
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "brightness",
.minimum = 0x00,
.maximum = 0xff,
.step = 0x01,
.default_value = S5K83A_DEFAULT_BRIGHTNESS,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = s5k83a_set_brightness,
.get = s5k83a_get_brightness,
},
#define EXPOSURE_IDX 2
{
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "exposure",
.minimum = 0x00,
.maximum = S5K83A_MAXIMUM_EXPOSURE,
.step = 0x01,
.default_value = S5K83A_DEFAULT_EXPOSURE,
.flags = V4L2_CTRL_FLAG_SLIDER
},
.set = s5k83a_set_exposure,
.get = s5k83a_get_exposure
},
#define HFLIP_IDX 3
{
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "horizontal flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = s5k83a_set_hflip,
.get = s5k83a_get_hflip
},
#define VFLIP_IDX 4
{
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "vertical flip",
.minimum = 0,
.maximum = 1,
.step = 1,
.default_value = 0
},
.set = s5k83a_set_vflip,
.get = s5k83a_get_vflip
}
};
static void s5k83a_dump_registers(struct sd *sd); static void s5k83a_dump_registers(struct sd *sd);
static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data); static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
static int s5k83a_set_led_indication(struct sd *sd, u8 val); static int s5k83a_set_led_indication(struct sd *sd, u8 val);
@ -131,7 +49,6 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
int s5k83a_probe(struct sd *sd) int s5k83a_probe(struct sd *sd)
{ {
struct s5k83a_priv *sens_priv;
u8 prod_id = 0, ver_id = 0; u8 prod_id = 0, ver_id = 0;
int i, err = 0; int i, err = 0;
@ -173,38 +90,18 @@ int s5k83a_probe(struct sd *sd)
pr_info("Detected a s5k83a sensor\n"); pr_info("Detected a s5k83a sensor\n");
sensor_found: sensor_found:
sens_priv = kmalloc(
sizeof(struct s5k83a_priv), GFP_KERNEL);
if (!sens_priv)
return -ENOMEM;
sens_priv->settings =
kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);
if (!sens_priv->settings) {
kfree(sens_priv);
return -ENOMEM;
}
sd->gspca_dev.cam.cam_mode = s5k83a_modes; sd->gspca_dev.cam.cam_mode = s5k83a_modes;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes); sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);
sd->desc->ctrls = s5k83a_ctrls;
sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);
/* null the pointer! thread is't running now */ /* null the pointer! thread is't running now */
sens_priv->rotation_thread = NULL; sd->rotation_thread = NULL;
for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)
sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;
sd->sensor_priv = sens_priv;
return 0; return 0;
} }
int s5k83a_init(struct sd *sd) int s5k83a_init(struct sd *sd)
{ {
int i, err = 0; int i, err = 0;
s32 *sensor_settings =
((struct s5k83a_priv *) sd->sensor_priv)->settings;
for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) { for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
u8 data[2] = {0x00, 0x00}; u8 data[2] = {0x00, 0x00};
@ -237,33 +134,44 @@ int s5k83a_init(struct sd *sd)
if (dump_sensor) if (dump_sensor)
s5k83a_dump_registers(sd); s5k83a_dump_registers(sd);
err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
if (err < 0)
return err;
err = s5k83a_set_brightness(&sd->gspca_dev,
sensor_settings[BRIGHTNESS_IDX]);
if (err < 0)
return err;
err = s5k83a_set_exposure(&sd->gspca_dev,
sensor_settings[EXPOSURE_IDX]);
if (err < 0)
return err;
err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
if (err < 0)
return err;
err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
return err; return err;
} }
int s5k83a_init_controls(struct sd *sd)
{
struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
sd->gspca_dev.vdev.ctrl_handler = hdl;
v4l2_ctrl_handler_init(hdl, 6);
v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_BRIGHTNESS,
0, 255, 1, S5K83A_DEFAULT_BRIGHTNESS);
v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_EXPOSURE,
0, S5K83A_MAXIMUM_EXPOSURE, 1,
S5K83A_DEFAULT_EXPOSURE);
v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_GAIN,
0, 255, 1, S5K83A_DEFAULT_GAIN);
sd->hflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_HFLIP,
0, 1, 1, 0);
sd->vflip = v4l2_ctrl_new_std(hdl, &s5k83a_ctrl_ops, V4L2_CID_VFLIP,
0, 1, 1, 0);
if (hdl->error) {
pr_err("Could not initialize controls\n");
return hdl->error;
}
v4l2_ctrl_cluster(2, &sd->hflip);
return 0;
}
static int rotation_thread_function(void *data) static int rotation_thread_function(void *data)
{ {
struct sd *sd = (struct sd *) data; struct sd *sd = (struct sd *) data;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
u8 reg, previous_rotation = 0; u8 reg, previous_rotation = 0;
__s32 vflip, hflip; __s32 vflip, hflip;
@ -277,8 +185,8 @@ static int rotation_thread_function(void *data)
previous_rotation = reg; previous_rotation = reg;
pr_info("Camera was flipped\n"); pr_info("Camera was flipped\n");
s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); hflip = sd->hflip->val;
s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); vflip = sd->vflip->val;
if (reg) { if (reg) {
vflip = !vflip; vflip = !vflip;
@ -294,26 +202,25 @@ static int rotation_thread_function(void *data)
/* return to "front" flip */ /* return to "front" flip */
if (previous_rotation) { if (previous_rotation) {
s5k83a_get_vflip((struct gspca_dev *) sd, &vflip); hflip = sd->hflip->val;
s5k83a_get_hflip((struct gspca_dev *) sd, &hflip); vflip = sd->vflip->val;
s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip); s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
} }
sens_priv->rotation_thread = NULL; sd->rotation_thread = NULL;
return 0; return 0;
} }
int s5k83a_start(struct sd *sd) int s5k83a_start(struct sd *sd)
{ {
int i, err = 0; int i, err = 0;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
/* Create another thread, polling the GPIO ports of the camera to check /* Create another thread, polling the GPIO ports of the camera to check
if it got rotated. This is how the windows driver does it so we have if it got rotated. This is how the windows driver does it so we have
to assume that there is no better way of accomplishing this */ to assume that there is no better way of accomplishing this */
sens_priv->rotation_thread = kthread_create(rotation_thread_function, sd->rotation_thread = kthread_create(rotation_thread_function,
sd, "rotation thread"); sd, "rotation thread");
wake_up_process(sens_priv->rotation_thread); wake_up_process(sd->rotation_thread);
/* Preinit the sensor */ /* Preinit the sensor */
for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) { for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {
@ -333,32 +240,17 @@ int s5k83a_start(struct sd *sd)
int s5k83a_stop(struct sd *sd) int s5k83a_stop(struct sd *sd)
{ {
struct s5k83a_priv *sens_priv = sd->sensor_priv; if (sd->rotation_thread)
kthread_stop(sd->rotation_thread);
if (sens_priv->rotation_thread)
kthread_stop(sens_priv->rotation_thread);
return s5k83a_set_led_indication(sd, 0); return s5k83a_set_led_indication(sd, 0);
} }
void s5k83a_disconnect(struct sd *sd) void s5k83a_disconnect(struct sd *sd)
{ {
struct s5k83a_priv *sens_priv = sd->sensor_priv;
s5k83a_stop(sd); s5k83a_stop(sd);
sd->sensor = NULL; sd->sensor = NULL;
kfree(sens_priv->settings);
kfree(sens_priv);
}
static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
*val = sens_priv->settings[GAIN_IDX];
return 0;
} }
static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val) static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
@ -366,9 +258,6 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
int err; int err;
u8 data[2]; u8 data[2];
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
sens_priv->settings[GAIN_IDX] = val;
data[0] = 0x00; data[0] = 0x00;
data[1] = 0x20; data[1] = 0x20;
@ -391,60 +280,29 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
return err; return err;
} }
static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
*val = sens_priv->settings[BRIGHTNESS_IDX];
return 0;
}
static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val) static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 data[1]; u8 data[1];
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
sens_priv->settings[BRIGHTNESS_IDX] = val;
data[0] = val; data[0] = val;
err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1); err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
return err; return err;
} }
static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
*val = sens_priv->settings[EXPOSURE_IDX];
return 0;
}
static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val) static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
{ {
int err; int err;
u8 data[2]; u8 data[2];
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
sens_priv->settings[EXPOSURE_IDX] = val;
data[0] = 0; data[0] = 0;
data[1] = val; data[1] = val;
err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2); err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
return err; return err;
} }
static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
*val = sens_priv->settings[VFLIP_IDX];
return 0;
}
static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
__s32 vflip, __s32 hflip) __s32 vflip, __s32 hflip)
{ {
@ -476,60 +334,52 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
return err; return err;
} }
static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val) static int s5k83a_set_hvflip(struct gspca_dev *gspca_dev)
{ {
int err; int err;
u8 reg; u8 reg;
__s32 hflip;
struct sd *sd = (struct sd *) gspca_dev; struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv; int hflip = sd->hflip->val;
int vflip = sd->vflip->val;
sens_priv->settings[VFLIP_IDX] = val;
s5k83a_get_hflip(gspca_dev, &hflip);
err = s5k83a_get_rotation(sd, &reg); err = s5k83a_get_rotation(sd, &reg);
if (err < 0) if (err < 0)
return err; return err;
if (reg) { if (reg) {
val = !val;
hflip = !hflip; hflip = !hflip;
}
err = s5k83a_set_flip_real(gspca_dev, val, hflip);
return err;
}
static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
*val = sens_priv->settings[HFLIP_IDX];
return 0;
}
static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
{
int err;
u8 reg;
__s32 vflip;
struct sd *sd = (struct sd *) gspca_dev;
struct s5k83a_priv *sens_priv = sd->sensor_priv;
sens_priv->settings[HFLIP_IDX] = val;
s5k83a_get_vflip(gspca_dev, &vflip);
err = s5k83a_get_rotation(sd, &reg);
if (err < 0)
return err;
if (reg) {
val = !val;
vflip = !vflip; vflip = !vflip;
} }
err = s5k83a_set_flip_real(gspca_dev, vflip, val); err = s5k83a_set_flip_real(gspca_dev, vflip, hflip);
return err;
}
static int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct gspca_dev *gspca_dev =
container_of(ctrl->handler, struct gspca_dev, ctrl_handler);
int err;
if (!gspca_dev->streaming)
return 0;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
err = s5k83a_set_brightness(gspca_dev, ctrl->val);
break;
case V4L2_CID_EXPOSURE:
err = s5k83a_set_exposure(gspca_dev, ctrl->val);
break;
case V4L2_CID_GAIN:
err = s5k83a_set_gain(gspca_dev, ctrl->val);
break;
case V4L2_CID_HFLIP:
err = s5k83a_set_hvflip(gspca_dev);
break;
default:
return -EINVAL;
}
return err; return err;
} }

View File

@ -45,6 +45,7 @@ extern bool dump_sensor;
int s5k83a_probe(struct sd *sd); int s5k83a_probe(struct sd *sd);
int s5k83a_init(struct sd *sd); int s5k83a_init(struct sd *sd);
int s5k83a_init_controls(struct sd *sd);
int s5k83a_start(struct sd *sd); int s5k83a_start(struct sd *sd);
int s5k83a_stop(struct sd *sd); int s5k83a_stop(struct sd *sd);
void s5k83a_disconnect(struct sd *sd); void s5k83a_disconnect(struct sd *sd);
@ -53,6 +54,7 @@ static const struct m5602_sensor s5k83a = {
.name = "S5K83A", .name = "S5K83A",
.probe = s5k83a_probe, .probe = s5k83a_probe,
.init = s5k83a_init, .init = s5k83a_init,
.init_controls = s5k83a_init_controls,
.start = s5k83a_start, .start = s5k83a_start,
.stop = s5k83a_stop, .stop = s5k83a_stop,
.disconnect = s5k83a_disconnect, .disconnect = s5k83a_disconnect,
@ -60,13 +62,6 @@ static const struct m5602_sensor s5k83a = {
.i2c_regW = 2, .i2c_regW = 2,
}; };
struct s5k83a_priv {
/* We use another thread periodically
probing the orientation of the camera */
struct task_struct *rotation_thread;
s32 *settings;
};
static const unsigned char preinit_s5k83a[][4] = { static const unsigned char preinit_s5k83a[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00}, {BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},

View File

@ -57,6 +57,9 @@ struct m5602_sensor {
/* Performs a initialization sequence */ /* Performs a initialization sequence */
int (*init)(struct sd *sd); int (*init)(struct sd *sd);
/* Controls initialization, maybe NULL */
int (*init_controls)(struct sd *sd);
/* Executed when the camera starts to send data */ /* Executed when the camera starts to send data */
int (*start)(struct sd *sd); int (*start)(struct sd *sd);