mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-20 10:44:23 +08:00
[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:
parent
676fdd856b
commit
c84e412f6f
@ -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(
|
||||||
|
@ -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);
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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)
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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, ®);
|
err = s5k83a_get_rotation(sd, ®);
|
||||||
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, ®);
|
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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},
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user