mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-20 02:34: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 */
|
||||
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 */
|
||||
u8 frame_id;
|
||||
|
||||
/* The current 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(
|
||||
|
@ -252,6 +252,16 @@ static int m5602_init(struct gspca_dev *gspca_dev)
|
||||
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)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
/* sub-driver description, the ctrl and nctrl is filled at probe time */
|
||||
static struct sd_desc sd_desc = {
|
||||
/* sub-driver description */
|
||||
static const struct sd_desc sd_desc = {
|
||||
.name = MODULE_NAME,
|
||||
.config = m5602_configure,
|
||||
.init = m5602_init,
|
||||
.init_controls = m5602_init_controls,
|
||||
.start = m5602_start_transfer,
|
||||
.stopN = m5602_stop_transfer,
|
||||
.pkt_scan = m5602_urb_complete
|
||||
@ -355,7 +366,6 @@ static int m5602_configure(struct gspca_dev *gspca_dev,
|
||||
int err;
|
||||
|
||||
cam = &gspca_dev->cam;
|
||||
sd->desc = &sd_desc;
|
||||
|
||||
if (dump_bridge)
|
||||
m5602_dump_bridge(sd);
|
||||
|
@ -20,22 +20,8 @@
|
||||
|
||||
#include "m5602_mt9m111.h"
|
||||
|
||||
static int mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
|
||||
static int mt9m111_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
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 int mt9m111_s_ctrl(struct v4l2_ctrl *ctrl);
|
||||
static void mt9m111_dump_registers(struct sd *sd);
|
||||
|
||||
static struct v4l2_pix_format mt9m111_modes[] = {
|
||||
{
|
||||
@ -50,118 +36,26 @@ static struct v4l2_pix_format mt9m111_modes[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ctrl mt9m111_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 = 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 const struct v4l2_ctrl_ops mt9m111_ctrl_ops = {
|
||||
.s_ctrl = mt9m111_s_ctrl,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
u8 data[2] = {0x00, 0x00};
|
||||
int i;
|
||||
s32 *sensor_settings;
|
||||
|
||||
if (force_sensor) {
|
||||
if (force_sensor == MT9M111_SENSOR) {
|
||||
@ -200,19 +94,8 @@ int mt9m111_probe(struct sd *sd)
|
||||
return -ENODEV;
|
||||
|
||||
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.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;
|
||||
}
|
||||
@ -220,7 +103,6 @@ sensor_found:
|
||||
int mt9m111_init(struct sd *sd)
|
||||
{
|
||||
int i, err = 0;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
/* Init the sensor */
|
||||
for (i = 0; i < ARRAY_SIZE(init_mt9m111) && !err; i++) {
|
||||
@ -241,30 +123,45 @@ int mt9m111_init(struct sd *sd)
|
||||
if (dump_sensor)
|
||||
mt9m111_dump_registers(sd);
|
||||
|
||||
err = mt9m111_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = mt9m111_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
int mt9m111_init_controls(struct sd *sd)
|
||||
{
|
||||
struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
|
||||
|
||||
err = mt9m111_set_green_balance(&sd->gspca_dev,
|
||||
sensor_settings[GREEN_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->gspca_dev.vdev.ctrl_handler = hdl;
|
||||
v4l2_ctrl_handler_init(hdl, 7);
|
||||
|
||||
err = mt9m111_set_blue_balance(&sd->gspca_dev,
|
||||
sensor_settings[BLUE_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops,
|
||||
V4L2_CID_AUTO_WHITE_BALANCE,
|
||||
0, 1, 1, 0);
|
||||
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,
|
||||
sensor_settings[RED_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
v4l2_ctrl_new_std(hdl, &mt9m111_ctrl_ops, V4L2_CID_GAIN, 0,
|
||||
(INITIAL_MAX_GAIN - 1) * 2 * 2 * 2, 1,
|
||||
MT9M111_DEFAULT_GAIN);
|
||||
|
||||
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)
|
||||
@ -272,7 +169,6 @@ int mt9m111_start(struct sd *sd)
|
||||
int i, err = 0;
|
||||
u8 data[2];
|
||||
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 height = cam->cam_mode[sd->gspca_dev.curr_mode].height;
|
||||
@ -334,25 +230,10 @@ int mt9m111_start(struct sd *sd)
|
||||
switch (width) {
|
||||
case 640:
|
||||
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;
|
||||
|
||||
case 320:
|
||||
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;
|
||||
}
|
||||
return err;
|
||||
@ -361,105 +242,46 @@ int mt9m111_start(struct sd *sd)
|
||||
void mt9m111_disconnect(struct sd *sd)
|
||||
{
|
||||
sd->sensor = NULL;
|
||||
kfree(sd->sensor_priv);
|
||||
}
|
||||
|
||||
static int mt9m111_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 mt9m111_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
static int mt9m111_set_hvflip(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
int err;
|
||||
u8 data[2] = {0x00, 0x00};
|
||||
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);
|
||||
|
||||
sensor_settings[VFLIP_IDX] = val;
|
||||
PDEBUG(D_V4L2, "Set hvflip to %d %d", sd->hflip->val, sd->vflip->val);
|
||||
|
||||
/* The mt9m111 is flipped by default */
|
||||
val = !val;
|
||||
hflip = !sd->hflip->val;
|
||||
vflip = !sd->vflip->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] & 0xfe) | val;
|
||||
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
|
||||
data, 2);
|
||||
return err;
|
||||
}
|
||||
|
||||
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);
|
||||
data[0] = MT9M111_RMB_OVER_SIZED;
|
||||
if (gspca_dev->width == 640) {
|
||||
data[1] = MT9M111_RMB_ROW_SKIP_2X |
|
||||
MT9M111_RMB_COLUMN_SKIP_2X |
|
||||
(hflip << 1) | vflip;
|
||||
} else {
|
||||
data[1] = MT9M111_RMB_ROW_SKIP_4X |
|
||||
MT9M111_RMB_COLUMN_SKIP_4X |
|
||||
(hflip << 1) | vflip;
|
||||
}
|
||||
err = m5602_write_sensor(sd, MT9M111_SC_R_MODE_CONTEXT_B,
|
||||
data, 2);
|
||||
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,
|
||||
__s32 val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
int err;
|
||||
u8 data[2];
|
||||
|
||||
@ -467,7 +289,6 @@ static int mt9m111_set_auto_white_balance(struct gspca_dev *gspca_dev,
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val & 0x01;
|
||||
data[1] = ((data[1] & 0xfd) | ((val & 0x01) << 1));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int err, tmp;
|
||||
u8 data[2] = {0x00, 0x00};
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
sensor_settings[GAIN_IDX] = val;
|
||||
|
||||
/* Set the correct page map */
|
||||
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;
|
||||
u8 data[2];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
sensor_settings[GREEN_BALANCE_IDX] = val;
|
||||
data[1] = (val & 0xff);
|
||||
data[0] = (val & 0xff00) >> 8;
|
||||
|
||||
@ -548,23 +354,11 @@ static int mt9m111_set_green_balance(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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)
|
||||
{
|
||||
u8 data[2];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
sensor_settings[BLUE_BALANCE_IDX] = val;
|
||||
data[1] = (val & 0xff);
|
||||
data[0] = (val & 0xff00) >> 8;
|
||||
|
||||
@ -574,23 +368,11 @@ static int mt9m111_set_blue_balance(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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)
|
||||
{
|
||||
u8 data[2];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
sensor_settings[RED_BALANCE_IDX] = val;
|
||||
data[1] = (val & 0xff);
|
||||
data[0] = (val & 0xff00) >> 8;
|
||||
|
||||
@ -600,14 +382,40 @@ static int mt9m111_set_red_balance(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
int err;
|
||||
|
||||
*val = sensor_settings[RED_BALANCE_IDX];
|
||||
PDEBUG(D_V4L2, "Read red balance %d", *val);
|
||||
return 0;
|
||||
if (!gspca_dev->streaming)
|
||||
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)
|
||||
|
@ -110,6 +110,7 @@ extern bool dump_sensor;
|
||||
|
||||
int mt9m111_probe(struct sd *sd);
|
||||
int mt9m111_init(struct sd *sd);
|
||||
int mt9m111_init_controls(struct sd *sd);
|
||||
int mt9m111_start(struct sd *sd);
|
||||
void mt9m111_disconnect(struct sd *sd);
|
||||
|
||||
@ -121,6 +122,7 @@ static const struct m5602_sensor mt9m111 = {
|
||||
|
||||
.probe = mt9m111_probe,
|
||||
.init = mt9m111_init,
|
||||
.init_controls = mt9m111_init_controls,
|
||||
.disconnect = mt9m111_disconnect,
|
||||
.start = mt9m111_start,
|
||||
};
|
||||
|
@ -20,111 +20,8 @@
|
||||
|
||||
#include "m5602_ov7660.h"
|
||||
|
||||
static int ov7660_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
static int ov7660_set_gain(struct gspca_dev *gspca_dev, __s32 val);
|
||||
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 int ov7660_s_ctrl(struct v4l2_ctrl *ctrl);
|
||||
static void ov7660_dump_registers(struct sd *sd);
|
||||
|
||||
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 err = 0, i;
|
||||
u8 prod_id = 0, ver_id = 0;
|
||||
|
||||
s32 *sensor_settings;
|
||||
|
||||
if (force_sensor) {
|
||||
if (force_sensor == OV7660_SENSOR) {
|
||||
pr_info("Forcing an %s sensor\n", ov7660.name);
|
||||
@ -191,19 +88,8 @@ int ov7660_probe(struct sd *sd)
|
||||
return -ENODEV;
|
||||
|
||||
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.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;
|
||||
}
|
||||
@ -211,7 +97,6 @@ sensor_found:
|
||||
int ov7660_init(struct sd *sd)
|
||||
{
|
||||
int i, err = 0;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
/* Init the sensor */
|
||||
for (i = 0; i < ARRAY_SIZE(init_ov7660); i++) {
|
||||
@ -231,33 +116,40 @@ int ov7660_init(struct sd *sd)
|
||||
if (dump_sensor)
|
||||
ov7660_dump_registers(sd);
|
||||
|
||||
err = ov7660_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = ov7660_set_auto_white_balance(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_WHITE_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
int ov7660_init_controls(struct sd *sd)
|
||||
{
|
||||
struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
|
||||
|
||||
err = ov7660_set_auto_gain(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_GAIN_CTRL_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->gspca_dev.vdev.ctrl_handler = hdl;
|
||||
v4l2_ctrl_handler_init(hdl, 6);
|
||||
|
||||
err = ov7660_set_auto_exposure(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_EXPOSURE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = ov7660_set_hflip(&sd->gspca_dev,
|
||||
sensor_settings[HFLIP_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops, V4L2_CID_AUTO_WHITE_BALANCE,
|
||||
0, 1, 1, 1);
|
||||
v4l2_ctrl_new_std_menu(hdl, &ov7660_ctrl_ops,
|
||||
V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
|
||||
|
||||
err = ov7660_set_vflip(&sd->gspca_dev,
|
||||
sensor_settings[VFLIP_IDX]);
|
||||
sd->autogain = v4l2_ctrl_new_std(hdl, &ov7660_ctrl_ops,
|
||||
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)
|
||||
@ -275,56 +167,29 @@ void ov7660_disconnect(struct sd *sd)
|
||||
ov7660_stop(sd);
|
||||
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
u8 i2c_data = val;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Setting gain to %d", val);
|
||||
|
||||
sensor_settings[GAIN_IDX] = val;
|
||||
|
||||
err = m5602_write_sensor(sd, OV7660_GAIN, &i2c_data, 1);
|
||||
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,
|
||||
__s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -335,26 +200,14 @@ static int ov7660_set_auto_white_balance(struct gspca_dev *gspca_dev,
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
__s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val = (val == V4L2_EXPOSURE_AUTO);
|
||||
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
|
||||
|
||||
return m5602_write_sensor(sd, OV7660_COM8, &i2c_data, 1);
|
||||
}
|
||||
|
||||
static int ov7660_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 ov7660_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
static int ov7660_set_hvflip(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
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 = ((val & 0x01) << 5) |
|
||||
(sensor_settings[VFLIP_IDX] << 4);
|
||||
i2c_data = (sd->hflip->val << 5) | (sd->vflip->val << 4);
|
||||
|
||||
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
|
||||
|
||||
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;
|
||||
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;
|
||||
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 (!gspca_dev->streaming)
|
||||
return 0;
|
||||
|
||||
i2c_data = ((val & 0x01) << 4) | (sensor_settings[VFLIP_IDX] << 5);
|
||||
err = m5602_write_sensor(sd, OV7660_MVFP, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* When vflip is toggled we need to readjust the bridge hsync/vsync */
|
||||
if (gspca_dev->streaming)
|
||||
err = ov7660_start(sd);
|
||||
switch (ctrl->id) {
|
||||
case V4L2_CID_AUTO_WHITE_BALANCE:
|
||||
err = ov7660_set_auto_white_balance(gspca_dev, ctrl->val);
|
||||
break;
|
||||
case V4L2_CID_EXPOSURE_AUTO:
|
||||
err = ov7660_set_auto_exposure(gspca_dev, ctrl->val);
|
||||
break;
|
||||
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;
|
||||
}
|
||||
|
@ -90,6 +90,8 @@ extern bool dump_sensor;
|
||||
|
||||
int ov7660_probe(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_stop(struct sd *sd);
|
||||
void ov7660_disconnect(struct sd *sd);
|
||||
@ -100,6 +102,7 @@ static const struct m5602_sensor ov7660 = {
|
||||
.i2c_regW = 1,
|
||||
.probe = ov7660_probe,
|
||||
.init = ov7660_init,
|
||||
.init_controls = ov7660_init_controls,
|
||||
.start = ov7660_start,
|
||||
.stop = ov7660_stop,
|
||||
.disconnect = ov7660_disconnect,
|
||||
|
@ -20,26 +20,8 @@
|
||||
|
||||
#include "m5602_ov9650.h"
|
||||
|
||||
static int ov9650_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
|
||||
static int ov9650_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
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);
|
||||
static int ov9650_s_ctrl(struct v4l2_ctrl *ctrl);
|
||||
static void ov9650_dump_registers(struct sd *sd);
|
||||
|
||||
/* Vertically and horizontally flips the image if matched, needed for machines
|
||||
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[] = {
|
||||
{
|
||||
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 err = 0;
|
||||
u8 prod_id = 0, ver_id = 0, i;
|
||||
s32 *sensor_settings;
|
||||
|
||||
if (force_sensor) {
|
||||
if (force_sensor == OV9650_SENSOR) {
|
||||
@ -338,19 +187,9 @@ int ov9650_probe(struct sd *sd)
|
||||
return -ENODEV;
|
||||
|
||||
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.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;
|
||||
}
|
||||
|
||||
@ -358,7 +197,6 @@ int ov9650_init(struct sd *sd)
|
||||
{
|
||||
int i, err = 0;
|
||||
u8 data;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
if (dump_sensor)
|
||||
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 = ov9650_set_exposure(&sd->gspca_dev,
|
||||
sensor_settings[EXPOSURE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = ov9650_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
int ov9650_init_controls(struct sd *sd)
|
||||
{
|
||||
struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
|
||||
|
||||
err = ov9650_set_red_balance(&sd->gspca_dev,
|
||||
sensor_settings[RED_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->gspca_dev.vdev.ctrl_handler = hdl;
|
||||
v4l2_ctrl_handler_init(hdl, 9);
|
||||
|
||||
err = ov9650_set_blue_balance(&sd->gspca_dev,
|
||||
sensor_settings[BLUE_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
|
||||
V4L2_CID_AUTO_WHITE_BALANCE,
|
||||
0, 1, 1, 1);
|
||||
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]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &ov9650_ctrl_ops,
|
||||
V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_AUTO);
|
||||
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]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->autogain = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops,
|
||||
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
|
||||
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,
|
||||
sensor_settings[AUTO_EXPOSURE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->hflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_HFLIP,
|
||||
0, 1, 1, 0);
|
||||
sd->vflip = v4l2_ctrl_new_std(hdl, &ov9650_ctrl_ops, V4L2_CID_VFLIP,
|
||||
0, 1, 1, 0);
|
||||
|
||||
err = ov9650_set_auto_white_balance(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_WHITE_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (hdl->error) {
|
||||
pr_err("Could not initialize controls\n");
|
||||
return hdl->error;
|
||||
}
|
||||
|
||||
err = ov9650_set_auto_gain(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_GAIN_CTRL_IDX]);
|
||||
return err;
|
||||
v4l2_ctrl_auto_cluster(3, &sd->auto_white_bal, 0, false);
|
||||
v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
|
||||
v4l2_ctrl_auto_cluster(2, &sd->autogain, 0, false);
|
||||
v4l2_ctrl_cluster(2, &sd->hflip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ov9650_start(struct sd *sd)
|
||||
@ -419,7 +263,6 @@ int ov9650_start(struct sd *sd)
|
||||
u8 data;
|
||||
int i, err = 0;
|
||||
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 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;
|
||||
|
||||
if ((!dmi_check_system(ov9650_flip_dmi_table) &&
|
||||
sensor_settings[VFLIP_IDX]) ||
|
||||
sd->vflip->val) ||
|
||||
(dmi_check_system(ov9650_flip_dmi_table) &&
|
||||
!sensor_settings[VFLIP_IDX]))
|
||||
!sd->vflip->val))
|
||||
ver_offs--;
|
||||
|
||||
if (width <= 320)
|
||||
@ -553,29 +396,16 @@ void ov9650_disconnect(struct sd *sd)
|
||||
ov9650_stop(sd);
|
||||
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
PDEBUG(D_V4L2, "Set exposure to %d", val);
|
||||
|
||||
sensor_settings[EXPOSURE_IDX] = val;
|
||||
/* The 6 MSBs */
|
||||
i2c_data = (val >> 10) & 0x3f;
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Setting gain to %d", val);
|
||||
|
||||
sensor_settings[GAIN_IDX] = val;
|
||||
|
||||
/* The 2 MSB */
|
||||
/* Read the OV9650_VREF register first to avoid
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Set red gain to %d", val);
|
||||
|
||||
sensor_settings[RED_BALANCE_IDX] = val;
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
err = m5602_write_sensor(sd, OV9650_RED, &i2c_data, 1);
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
PDEBUG(D_V4L2, "Set blue gain to %d", val);
|
||||
|
||||
sensor_settings[BLUE_BALANCE_IDX] = val;
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
err = m5602_write_sensor(sd, OV9650_BLUE, &i2c_data, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ov9650_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 ov9650_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
static int ov9650_set_hvflip(struct gspca_dev *gspca_dev)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
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);
|
||||
|
||||
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;
|
||||
PDEBUG(D_V4L2, "Set hvflip to %d %d", hflip, vflip);
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -759,57 +505,34 @@ static int ov9650_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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,
|
||||
__s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
val = (val == V4L2_EXPOSURE_AUTO);
|
||||
i2c_data = ((i2c_data & 0xfe) | ((val & 0x01) << 0));
|
||||
|
||||
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,
|
||||
__s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -820,26 +543,14 @@ static int ov9650_set_auto_white_balance(struct gspca_dev *gspca_dev,
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u8 i2c_data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
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);
|
||||
if (err < 0)
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
int address;
|
||||
|
@ -139,6 +139,7 @@ extern bool dump_sensor;
|
||||
|
||||
int ov9650_probe(struct sd *sd);
|
||||
int ov9650_init(struct sd *sd);
|
||||
int ov9650_init_controls(struct sd *sd);
|
||||
int ov9650_start(struct sd *sd);
|
||||
int ov9650_stop(struct sd *sd);
|
||||
void ov9650_disconnect(struct sd *sd);
|
||||
@ -149,6 +150,7 @@ static const struct m5602_sensor ov9650 = {
|
||||
.i2c_regW = 1,
|
||||
.probe = ov9650_probe,
|
||||
.init = ov9650_init,
|
||||
.init_controls = ov9650_init_controls,
|
||||
.start = ov9650_start,
|
||||
.stop = ov9650_stop,
|
||||
.disconnect = ov9650_disconnect,
|
||||
|
@ -20,28 +20,8 @@
|
||||
|
||||
#include "m5602_po1030.h"
|
||||
|
||||
static int po1030_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
|
||||
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 int po1030_s_ctrl(struct v4l2_ctrl *ctrl);
|
||||
static void po1030_dump_registers(struct sd *sd);
|
||||
|
||||
static struct v4l2_pix_format po1030_modes[] = {
|
||||
{
|
||||
@ -56,146 +36,25 @@ static struct v4l2_pix_format po1030_modes[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct ctrl po1030_ctrls[] = {
|
||||
#define GAIN_IDX 0
|
||||
{
|
||||
{
|
||||
.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 const struct v4l2_ctrl_ops po1030_ctrl_ops = {
|
||||
.s_ctrl = po1030_s_ctrl,
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
u8 dev_id_h = 0, i;
|
||||
s32 *sensor_settings;
|
||||
|
||||
if (force_sensor) {
|
||||
if (force_sensor == PO1030_SENSOR) {
|
||||
@ -229,26 +88,14 @@ int po1030_probe(struct sd *sd)
|
||||
return -ENODEV;
|
||||
|
||||
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.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;
|
||||
}
|
||||
|
||||
int po1030_init(struct sd *sd)
|
||||
{
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
int i, err = 0;
|
||||
|
||||
/* Init the sensor */
|
||||
@ -279,46 +126,50 @@ int po1030_init(struct sd *sd)
|
||||
if (dump_sensor)
|
||||
po1030_dump_registers(sd);
|
||||
|
||||
err = po1030_set_exposure(&sd->gspca_dev,
|
||||
sensor_settings[EXPOSURE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = po1030_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
int po1030_init_controls(struct sd *sd)
|
||||
{
|
||||
struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
|
||||
|
||||
err = po1030_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->gspca_dev.vdev.ctrl_handler = hdl;
|
||||
v4l2_ctrl_handler_init(hdl, 9);
|
||||
|
||||
err = po1030_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->auto_white_bal = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops,
|
||||
V4L2_CID_AUTO_WHITE_BALANCE,
|
||||
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,
|
||||
sensor_settings[RED_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->autoexpo = v4l2_ctrl_new_std_menu(hdl, &po1030_ctrl_ops,
|
||||
V4L2_CID_EXPOSURE_AUTO, 1, 0, V4L2_EXPOSURE_MANUAL);
|
||||
sd->expo = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_EXPOSURE,
|
||||
0, 0x2ff, 1, PO1030_EXPOSURE_DEFAULT);
|
||||
|
||||
err = po1030_set_blue_balance(&sd->gspca_dev,
|
||||
sensor_settings[BLUE_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->gain = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_GAIN, 0,
|
||||
0x4f, 1, PO1030_GLOBAL_GAIN_DEFAULT);
|
||||
|
||||
err = po1030_set_green_balance(&sd->gspca_dev,
|
||||
sensor_settings[GREEN_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
sd->hflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_HFLIP,
|
||||
0, 1, 1, 0);
|
||||
sd->vflip = v4l2_ctrl_new_std(hdl, &po1030_ctrl_ops, V4L2_CID_VFLIP,
|
||||
0, 1, 1, 0);
|
||||
|
||||
err = po1030_set_auto_white_balance(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_WHITE_BALANCE_IDX]);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (hdl->error) {
|
||||
pr_err("Could not initialize controls\n");
|
||||
return hdl->error;
|
||||
}
|
||||
|
||||
err = po1030_set_auto_exposure(&sd->gspca_dev,
|
||||
sensor_settings[AUTO_EXPOSURE_IDX]);
|
||||
return err;
|
||||
v4l2_ctrl_auto_cluster(4, &sd->auto_white_bal, 0, false);
|
||||
v4l2_ctrl_auto_cluster(2, &sd->autoexpo, 0, false);
|
||||
v4l2_ctrl_cluster(2, &sd->hflip);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int po1030_start(struct sd *sd)
|
||||
@ -448,24 +299,12 @@ int po1030_start(struct sd *sd)
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
sensor_settings[EXPOSURE_IDX] = val;
|
||||
PDEBUG(D_V4L2, "Set exposure to %d", val & 0xffff);
|
||||
|
||||
i2c_data = ((val & 0xff00) >> 8);
|
||||
@ -486,25 +325,12 @@ static int po1030_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
sensor_settings[GAIN_IDX] = val;
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
PDEBUG(D_V4L2, "Set global gain to %d", i2c_data);
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
int err;
|
||||
|
||||
sensor_settings[HFLIP_IDX] = val;
|
||||
|
||||
PDEBUG(D_V4L2, "Set hflip %d", val);
|
||||
PDEBUG(D_V4L2, "Set hvflip %d %d", sd->hflip->val, sd->vflip->val);
|
||||
err = m5602_read_sensor(sd, PO1030_CONTROL2, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
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,
|
||||
&i2c_data, 1);
|
||||
@ -545,58 +358,12 @@ static int po1030_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
sensor_settings[RED_BALANCE_IDX] = val;
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
PDEBUG(D_V4L2, "Set red gain to %d", i2c_data);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
sensor_settings[BLUE_BALANCE_IDX] = val;
|
||||
|
||||
i2c_data = val & 0xff;
|
||||
PDEBUG(D_V4L2, "Set blue gain to %d", i2c_data);
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
sensor_settings[GREEN_BALANCE_IDX] = val;
|
||||
i2c_data = val & 0xff;
|
||||
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);
|
||||
}
|
||||
|
||||
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,
|
||||
__s32 val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
sensor_settings[AUTO_WHITE_BALANCE_IDX] = val;
|
||||
|
||||
err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -695,31 +420,19 @@ static int po1030_set_auto_white_balance(struct gspca_dev *gspca_dev,
|
||||
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,
|
||||
__s32 val)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 i2c_data;
|
||||
int err;
|
||||
|
||||
sensor_settings[AUTO_EXPOSURE_IDX] = val;
|
||||
err = m5602_read_sensor(sd, PO1030_AUTOCTRL1, &i2c_data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
PDEBUG(D_V4L2, "Set auto exposure to %d", val);
|
||||
val = (val == V4L2_EXPOSURE_AUTO);
|
||||
i2c_data = (i2c_data & 0xfd) | ((val & 0x01) << 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)
|
||||
{
|
||||
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)
|
||||
|
@ -151,6 +151,7 @@ extern bool dump_sensor;
|
||||
|
||||
int po1030_probe(struct sd *sd);
|
||||
int po1030_init(struct sd *sd);
|
||||
int po1030_init_controls(struct sd *sd);
|
||||
int po1030_start(struct sd *sd);
|
||||
void po1030_disconnect(struct sd *sd);
|
||||
|
||||
@ -162,6 +163,7 @@ static const struct m5602_sensor po1030 = {
|
||||
|
||||
.probe = po1030_probe,
|
||||
.init = po1030_init,
|
||||
.init_controls = po1030_init_controls,
|
||||
.start = po1030_start,
|
||||
.disconnect = po1030_disconnect,
|
||||
};
|
||||
|
@ -20,18 +20,12 @@
|
||||
|
||||
#include "m5602_s5k4aa.h"
|
||||
|
||||
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_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
|
||||
static int s5k4aa_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
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 int s5k4aa_s_ctrl(struct v4l2_ctrl *ctrl);
|
||||
static void s5k4aa_dump_registers(struct sd *sd);
|
||||
|
||||
static const struct v4l2_ctrl_ops s5k4aa_ctrl_ops = {
|
||||
.s_ctrl = s5k4aa_s_ctrl,
|
||||
};
|
||||
|
||||
static
|
||||
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)
|
||||
{
|
||||
u8 prod_id[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
const u8 expected_prod_id[6] = {0x00, 0x10, 0x00, 0x4b, 0x33, 0x75};
|
||||
int i, err = 0;
|
||||
s32 *sensor_settings;
|
||||
|
||||
if (force_sensor) {
|
||||
if (force_sensor == S5K4AA_SENSOR) {
|
||||
@ -303,19 +204,8 @@ int s5k4aa_probe(struct sd *sd)
|
||||
pr_info("Detected a s5k4aa sensor\n");
|
||||
|
||||
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.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;
|
||||
}
|
||||
@ -325,7 +215,6 @@ int s5k4aa_start(struct sd *sd)
|
||||
int i, err = 0;
|
||||
u8 data[2];
|
||||
struct cam *cam = &sd->gspca_dev.cam;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
|
||||
switch (cam->cam_mode[sd->gspca_dev.curr_mode].width) {
|
||||
case 1280:
|
||||
@ -359,9 +248,6 @@ int s5k4aa_start(struct sd *sd)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
err = s5k4aa_set_noise(&sd->gspca_dev, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
|
||||
case 640:
|
||||
@ -395,37 +281,12 @@ int s5k4aa_start(struct sd *sd)
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
err = s5k4aa_set_noise(&sd->gspca_dev, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = s5k4aa_set_exposure(&sd->gspca_dev,
|
||||
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]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s5k4aa_init(struct sd *sd)
|
||||
@ -466,13 +327,36 @@ int s5k4aa_init(struct sd *sd)
|
||||
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;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
struct v4l2_ctrl_handler *hdl = &sd->gspca_dev.ctrl_handler;
|
||||
|
||||
*val = sensor_settings[EXPOSURE_IDX];
|
||||
PDEBUG(D_V4L2, "Read exposure %d", *val);
|
||||
sd->gspca_dev.vdev.ctrl_handler = hdl;
|
||||
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;
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 data = S5K4AA_PAGE_MAP_2;
|
||||
int err;
|
||||
|
||||
sensor_settings[EXPOSURE_IDX] = val;
|
||||
PDEBUG(D_V4L2, "Set exposure to %d", val);
|
||||
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
if (err < 0)
|
||||
@ -499,27 +381,15 @@ static int s5k4aa_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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;
|
||||
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;
|
||||
int err;
|
||||
int hflip = sd->hflip->val;
|
||||
int vflip = sd->vflip->val;
|
||||
|
||||
sensor_settings[VFLIP_IDX] = val;
|
||||
|
||||
PDEBUG(D_V4L2, "Set vertical flip to %d", val);
|
||||
PDEBUG(D_V4L2, "Set hvflip %d %d", hflip, vflip);
|
||||
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
@ -528,58 +398,12 @@ static int s5k4aa_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (dmi_check_system(s5k4aa_vflip_dmi_table))
|
||||
val = !val;
|
||||
if (dmi_check_system(s5k4aa_vflip_dmi_table)) {
|
||||
hflip = !hflip;
|
||||
vflip = !vflip;
|
||||
}
|
||||
|
||||
data = ((data & ~S5K4AA_RM_V_FLIP) | ((val & 0x01) << 7));
|
||||
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));
|
||||
data = (data & 0x7f) | (vflip << 7) | (hflip << 6);
|
||||
err = m5602_write_sensor(sd, S5K4AA_READ_MODE, &data, 1);
|
||||
if (err < 0)
|
||||
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);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (val)
|
||||
if (hflip)
|
||||
data &= 0xfe;
|
||||
else
|
||||
data |= 0x01;
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
err = m5602_read_sensor(sd, S5K4AA_ROWSTART_LO, &data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
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;
|
||||
}
|
||||
|
||||
static int s5k4aa_set_gain(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[GAIN_IDX] = val;
|
||||
|
||||
PDEBUG(D_V4L2, "Set gain to %d", val);
|
||||
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
if (err < 0)
|
||||
@ -625,25 +450,12 @@ static int s5k4aa_set_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 data = S5K4AA_PAGE_MAP_2;
|
||||
int err;
|
||||
|
||||
sensor_settings[BRIGHTNESS_IDX] = val;
|
||||
|
||||
PDEBUG(D_V4L2, "Set brightness to %d", val);
|
||||
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
s32 *sensor_settings = sd->sensor_priv;
|
||||
u8 data = S5K4AA_PAGE_MAP_2;
|
||||
int err;
|
||||
|
||||
sensor_settings[NOISE_SUPP_IDX] = val;
|
||||
|
||||
PDEBUG(D_V4L2, "Set noise to %d", val);
|
||||
err = m5602_write_sensor(sd, S5K4AA_PAGE_MAP, &data, 1);
|
||||
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);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
sd->sensor = NULL;
|
||||
kfree(sd->sensor_priv);
|
||||
}
|
||||
|
||||
static void s5k4aa_dump_registers(struct sd *sd)
|
||||
|
@ -69,6 +69,7 @@ extern bool dump_sensor;
|
||||
|
||||
int s5k4aa_probe(struct sd *sd);
|
||||
int s5k4aa_init(struct sd *sd);
|
||||
int s5k4aa_init_controls(struct sd *sd);
|
||||
int s5k4aa_start(struct sd *sd);
|
||||
void s5k4aa_disconnect(struct sd *sd);
|
||||
|
||||
@ -79,6 +80,7 @@ static const struct m5602_sensor s5k4aa = {
|
||||
|
||||
.probe = s5k4aa_probe,
|
||||
.init = s5k4aa_init,
|
||||
.init_controls = s5k4aa_init_controls,
|
||||
.start = s5k4aa_start,
|
||||
.disconnect = s5k4aa_disconnect,
|
||||
};
|
||||
|
@ -21,16 +21,11 @@
|
||||
#include <linux/kthread.h>
|
||||
#include "m5602_s5k83a.h"
|
||||
|
||||
static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
|
||||
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 int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
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 int s5k83a_s_ctrl(struct v4l2_ctrl *ctrl);
|
||||
|
||||
static const struct v4l2_ctrl_ops s5k83a_ctrl_ops = {
|
||||
.s_ctrl = s5k83a_s_ctrl,
|
||||
};
|
||||
|
||||
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 int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);
|
||||
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)
|
||||
{
|
||||
struct s5k83a_priv *sens_priv;
|
||||
u8 prod_id = 0, ver_id = 0;
|
||||
int i, err = 0;
|
||||
|
||||
@ -173,38 +90,18 @@ int s5k83a_probe(struct sd *sd)
|
||||
pr_info("Detected a s5k83a sensor\n");
|
||||
|
||||
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.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 */
|
||||
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;
|
||||
}
|
||||
|
||||
int s5k83a_init(struct sd *sd)
|
||||
{
|
||||
int i, err = 0;
|
||||
s32 *sensor_settings =
|
||||
((struct s5k83a_priv *) sd->sensor_priv)->settings;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {
|
||||
u8 data[2] = {0x00, 0x00};
|
||||
@ -237,33 +134,44 @@ int s5k83a_init(struct sd *sd)
|
||||
if (dump_sensor)
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
struct sd *sd = (struct sd *) data;
|
||||
struct s5k83a_priv *sens_priv = sd->sensor_priv;
|
||||
u8 reg, previous_rotation = 0;
|
||||
__s32 vflip, hflip;
|
||||
|
||||
@ -277,8 +185,8 @@ static int rotation_thread_function(void *data)
|
||||
previous_rotation = reg;
|
||||
pr_info("Camera was flipped\n");
|
||||
|
||||
s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
|
||||
s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
|
||||
hflip = sd->hflip->val;
|
||||
vflip = sd->vflip->val;
|
||||
|
||||
if (reg) {
|
||||
vflip = !vflip;
|
||||
@ -294,26 +202,25 @@ static int rotation_thread_function(void *data)
|
||||
|
||||
/* return to "front" flip */
|
||||
if (previous_rotation) {
|
||||
s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
|
||||
s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
|
||||
hflip = sd->hflip->val;
|
||||
vflip = sd->vflip->val;
|
||||
s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
|
||||
}
|
||||
|
||||
sens_priv->rotation_thread = NULL;
|
||||
sd->rotation_thread = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s5k83a_start(struct sd *sd)
|
||||
{
|
||||
int i, err = 0;
|
||||
struct s5k83a_priv *sens_priv = sd->sensor_priv;
|
||||
|
||||
/* 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
|
||||
to assume that there is no better way of accomplishing this */
|
||||
sens_priv->rotation_thread = kthread_create(rotation_thread_function,
|
||||
sd, "rotation thread");
|
||||
wake_up_process(sens_priv->rotation_thread);
|
||||
sd->rotation_thread = kthread_create(rotation_thread_function,
|
||||
sd, "rotation thread");
|
||||
wake_up_process(sd->rotation_thread);
|
||||
|
||||
/* Preinit the sensor */
|
||||
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)
|
||||
{
|
||||
struct s5k83a_priv *sens_priv = sd->sensor_priv;
|
||||
|
||||
if (sens_priv->rotation_thread)
|
||||
kthread_stop(sens_priv->rotation_thread);
|
||||
if (sd->rotation_thread)
|
||||
kthread_stop(sd->rotation_thread);
|
||||
|
||||
return s5k83a_set_led_indication(sd, 0);
|
||||
}
|
||||
|
||||
void s5k83a_disconnect(struct sd *sd)
|
||||
{
|
||||
struct s5k83a_priv *sens_priv = sd->sensor_priv;
|
||||
|
||||
s5k83a_stop(sd);
|
||||
|
||||
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)
|
||||
@ -366,9 +258,6 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
int err;
|
||||
u8 data[2];
|
||||
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[1] = 0x20;
|
||||
@ -391,60 +280,29 @@ static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u8 data[1];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
struct s5k83a_priv *sens_priv = sd->sensor_priv;
|
||||
|
||||
sens_priv->settings[BRIGHTNESS_IDX] = val;
|
||||
data[0] = val;
|
||||
err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);
|
||||
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)
|
||||
{
|
||||
int err;
|
||||
u8 data[2];
|
||||
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[1] = val;
|
||||
err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);
|
||||
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,
|
||||
__s32 vflip, __s32 hflip)
|
||||
{
|
||||
@ -476,60 +334,52 @@ static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,
|
||||
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;
|
||||
u8 reg;
|
||||
__s32 hflip;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
struct s5k83a_priv *sens_priv = sd->sensor_priv;
|
||||
|
||||
sens_priv->settings[VFLIP_IDX] = val;
|
||||
|
||||
s5k83a_get_hflip(gspca_dev, &hflip);
|
||||
int hflip = sd->hflip->val;
|
||||
int vflip = sd->vflip->val;
|
||||
|
||||
err = s5k83a_get_rotation(sd, ®);
|
||||
if (err < 0)
|
||||
return err;
|
||||
if (reg) {
|
||||
val = !val;
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -45,6 +45,7 @@ extern bool dump_sensor;
|
||||
|
||||
int s5k83a_probe(struct sd *sd);
|
||||
int s5k83a_init(struct sd *sd);
|
||||
int s5k83a_init_controls(struct sd *sd);
|
||||
int s5k83a_start(struct sd *sd);
|
||||
int s5k83a_stop(struct sd *sd);
|
||||
void s5k83a_disconnect(struct sd *sd);
|
||||
@ -53,6 +54,7 @@ static const struct m5602_sensor s5k83a = {
|
||||
.name = "S5K83A",
|
||||
.probe = s5k83a_probe,
|
||||
.init = s5k83a_init,
|
||||
.init_controls = s5k83a_init_controls,
|
||||
.start = s5k83a_start,
|
||||
.stop = s5k83a_stop,
|
||||
.disconnect = s5k83a_disconnect,
|
||||
@ -60,13 +62,6 @@ static const struct m5602_sensor s5k83a = {
|
||||
.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] = {
|
||||
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
|
||||
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
|
||||
|
@ -57,6 +57,9 @@ struct m5602_sensor {
|
||||
/* Performs a initialization sequence */
|
||||
int (*init)(struct sd *sd);
|
||||
|
||||
/* Controls initialization, maybe NULL */
|
||||
int (*init_controls)(struct sd *sd);
|
||||
|
||||
/* Executed when the camera starts to send data */
|
||||
int (*start)(struct sd *sd);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user