mirror of https://gitee.com/openkylin/linux.git
V4L/DVB (11451): gspca - m5602-s5k83a: Add rotation, ctrl cache. Rename some ctrls.
s5k83a sensor mounted on many acer laptops have a swiwel allowing it to be rotated. When the camera is in its rotated state, the image needs to be flipped. The only way to check for if the camera has been flipped is to continously poll a register in the m5602. This patch creates a kernel thread which does this. This patch renames some v4l2 ctrls and finally implements a cache in order to prevent unnecessary sensor reads. Signed-off-by: Luk?? Karas <lukas.karas@centrum.cz> Signed-off-by: Erik Andr?n <erik.andren@gmail.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
parent
04f15655f6
commit
ac3d5bfecc
|
@ -80,6 +80,16 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
|
|||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
int m5602_wait_for_i2c(struct sd *sd)
|
||||
{
|
||||
int err;
|
||||
u8 data;
|
||||
do {
|
||||
err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, &data);
|
||||
} while ((data & I2C_BUSY) && !err);
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
int m5602_read_sensor(struct sd *sd, const u8 address,
|
||||
u8 *i2c_data, const u8 len)
|
||||
{
|
||||
|
@ -88,9 +98,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
|
|||
if (!len || len > sd->sensor->i2c_regW)
|
||||
return -EINVAL;
|
||||
|
||||
do {
|
||||
err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
|
||||
} while ((*i2c_data & I2C_BUSY) && !err);
|
||||
err = m5602_wait_for_i2c(sd);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
|
@ -118,6 +126,10 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
|
|||
}
|
||||
|
||||
for (i = 0; (i < len) && !err; i++) {
|
||||
err = m5602_wait_for_i2c(sd);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
|
||||
|
||||
PDEBUG(D_CONF, "Reading sensor register "
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/kthread.h>
|
||||
#include "m5602_s5k83a.h"
|
||||
|
||||
static struct v4l2_pix_format s5k83a_modes[] = {
|
||||
|
@ -33,6 +34,23 @@ static struct v4l2_pix_format s5k83a_modes[] = {
|
|||
};
|
||||
|
||||
const static 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,
|
||||
|
@ -45,35 +63,25 @@ const static struct ctrl s5k83a_ctrls[] = {
|
|||
.flags = V4L2_CTRL_FLAG_SLIDER
|
||||
},
|
||||
.set = s5k83a_set_brightness,
|
||||
.get = s5k83a_get_brightness
|
||||
|
||||
}, {
|
||||
.get = s5k83a_get_brightness,
|
||||
},
|
||||
#define EXPOSURE_IDX 2
|
||||
{
|
||||
{
|
||||
.id = V4L2_CID_WHITENESS,
|
||||
.id = V4L2_CID_EXPOSURE,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "whiteness",
|
||||
.name = "exposure",
|
||||
.minimum = 0x00,
|
||||
.maximum = 0xff,
|
||||
.maximum = S5K83A_MAXIMUM_EXPOSURE,
|
||||
.step = 0x01,
|
||||
.default_value = S5K83A_DEFAULT_WHITENESS,
|
||||
.default_value = S5K83A_DEFAULT_EXPOSURE,
|
||||
.flags = V4L2_CTRL_FLAG_SLIDER
|
||||
},
|
||||
.set = s5k83a_set_whiteness,
|
||||
.get = s5k83a_get_whiteness,
|
||||
}, {
|
||||
{
|
||||
.id = V4L2_CID_GAIN,
|
||||
.type = V4L2_CTRL_TYPE_INTEGER,
|
||||
.name = "gain",
|
||||
.minimum = 0x00,
|
||||
.maximum = S5K83A_MAXIMUM_GAIN,
|
||||
.step = 0x01,
|
||||
.default_value = S5K83A_DEFAULT_GAIN,
|
||||
.flags = V4L2_CTRL_FLAG_SLIDER
|
||||
},
|
||||
.set = s5k83a_set_gain,
|
||||
.get = s5k83a_get_gain
|
||||
}, {
|
||||
.set = s5k83a_set_exposure,
|
||||
.get = s5k83a_get_exposure
|
||||
},
|
||||
#define HFLIP_IDX 3
|
||||
{
|
||||
{
|
||||
.id = V4L2_CID_HFLIP,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
|
@ -85,7 +93,9 @@ const static struct ctrl s5k83a_ctrls[] = {
|
|||
},
|
||||
.set = s5k83a_set_hflip,
|
||||
.get = s5k83a_get_hflip
|
||||
}, {
|
||||
},
|
||||
#define VFLIP_IDX 4
|
||||
{
|
||||
{
|
||||
.id = V4L2_CID_VFLIP,
|
||||
.type = V4L2_CTRL_TYPE_BOOLEAN,
|
||||
|
@ -101,9 +111,13 @@ const static struct ctrl s5k83a_ctrls[] = {
|
|||
};
|
||||
|
||||
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);
|
||||
int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, __s32 vflip, __s32 hflip);
|
||||
|
||||
int s5k83a_probe(struct sd *sd)
|
||||
{
|
||||
struct s5k83a_priv *sens_priv;
|
||||
u8 prod_id = 0, ver_id = 0;
|
||||
int i, err = 0;
|
||||
|
||||
|
@ -145,10 +159,28 @@ int s5k83a_probe(struct sd *sd)
|
|||
info("Detected a s5k83a sensor");
|
||||
|
||||
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)
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -190,21 +222,294 @@ int s5k83a_init(struct sd *sd)
|
|||
return (err < 0) ? err : 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;
|
||||
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
while (!schedule_timeout(100)) {
|
||||
if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))
|
||||
break;
|
||||
|
||||
s5k83a_get_rotation(sd, ®);
|
||||
if (previous_rotation != reg) {
|
||||
previous_rotation = reg;
|
||||
info("Camera was flipped");
|
||||
|
||||
s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
|
||||
s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
|
||||
|
||||
if (reg) {
|
||||
vflip = !vflip;
|
||||
hflip = !hflip;
|
||||
}
|
||||
s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
|
||||
}
|
||||
|
||||
mutex_unlock(&sd->gspca_dev.usb_lock);
|
||||
set_current_state(TASK_INTERRUPTIBLE);
|
||||
}
|
||||
|
||||
/* return to "front" flip */
|
||||
if (previous_rotation) {
|
||||
s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);
|
||||
s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);
|
||||
s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);
|
||||
}
|
||||
|
||||
sens_priv->rotation_thread = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int s5k83a_start(struct sd *sd)
|
||||
{
|
||||
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);
|
||||
|
||||
return s5k83a_set_led_indication(sd, 1);
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
int s5k83a_power_down(struct sd *sd)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
err = m5602_write_sensor(sd, 0x14, data, 2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data[0] = 0x01;
|
||||
data[1] = 0x00;
|
||||
err = m5602_write_sensor(sd, 0x0d, data, 2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* FIXME: This is not sane, we need to figure out the composition
|
||||
of these registers */
|
||||
data[0] = val >> 3; /* gain, high 5 bits */
|
||||
data[1] = val >> 1; /* gain, high 7 bits */
|
||||
err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
int s5k83a_set_flip_real(struct gspca_dev *gspca_dev, __s32 vflip, __s32 hflip)
|
||||
{
|
||||
int err;
|
||||
u8 data[1];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
data[0] = 0x05;
|
||||
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* six bit is vflip, seven is hflip */
|
||||
data[0] = S5K83A_FLIP_MASK;
|
||||
data[0] = (vflip) ? data[0] | 0x40 : data[0];
|
||||
data[0] = (hflip) ? data[0] | 0x80 : data[0];
|
||||
|
||||
err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data[0] = (vflip) ? 0x0b : 0x0a;
|
||||
err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data[0] = (hflip) ? 0x0a : 0x0b;
|
||||
err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int s5k83a_set_led_indication(struct sd *sd, u8 val)
|
||||
{
|
||||
int err = 0;
|
||||
u8 data[1];
|
||||
|
||||
err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (val)
|
||||
data[0] = data[0] | S5K83A_GPIO_LED_MASK;
|
||||
else
|
||||
data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
|
||||
|
||||
err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
||||
/* Get camera rotation on Acer notebooks */
|
||||
static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)
|
||||
{
|
||||
int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);
|
||||
*reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;
|
||||
return err;
|
||||
}
|
||||
|
||||
static void s5k83a_dump_registers(struct sd *sd)
|
||||
{
|
||||
int address;
|
||||
|
@ -226,7 +531,7 @@ static void s5k83a_dump_registers(struct sd *sd)
|
|||
for (page = 0; page < 16; page++) {
|
||||
m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);
|
||||
info("Probing for which registers that are read/write "
|
||||
"for page 0x%x", page);
|
||||
"for page 0x%x", page);
|
||||
for (address = 0; address <= 0xff; address++) {
|
||||
u8 old_val, ctrl_val, test_val = 0xff;
|
||||
|
||||
|
@ -246,213 +551,3 @@ static void s5k83a_dump_registers(struct sd *sd)
|
|||
info("Read/write register probing complete");
|
||||
m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);
|
||||
}
|
||||
|
||||
int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
int err;
|
||||
u8 data[2];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
err = m5602_read_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data[1] = data[1] << 1;
|
||||
*val = data[1];
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 data[2];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
data[0] = 0x00;
|
||||
data[1] = 0x20;
|
||||
err = m5602_write_sensor(sd, 0x14, data, 2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data[0] = 0x01;
|
||||
data[1] = 0x00;
|
||||
err = m5602_write_sensor(sd, 0x0d, data, 2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* FIXME: This is not sane, we need to figure out the composition
|
||||
of these registers */
|
||||
data[0] = val >> 3; /* brightness, high 5 bits */
|
||||
data[1] = val >> 1; /* brightness, high 7 bits */
|
||||
err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 2);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
int err;
|
||||
u8 data;
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
err = m5602_read_sensor(sd, S5K83A_WHITENESS, &data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
*val = data;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 data[1];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
data[0] = val;
|
||||
err = m5602_write_sensor(sd, S5K83A_WHITENESS, data, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
int err;
|
||||
u8 data[2];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
err = m5602_read_sensor(sd, S5K83A_GAIN, data, 2);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data[1] = data[1] & 0x3f;
|
||||
if (data[1] > S5K83A_MAXIMUM_GAIN)
|
||||
data[1] = S5K83A_MAXIMUM_GAIN;
|
||||
|
||||
*val = data[1];
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 data[2];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
data[0] = 0;
|
||||
data[1] = val;
|
||||
err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
int err;
|
||||
u8 data[1];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
data[0] = 0x05;
|
||||
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
|
||||
*val = (data[0] | 0x40) ? 1 : 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 data[1];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
data[0] = 0x05;
|
||||
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* set or zero six bit, seven is hflip */
|
||||
data[0] = (val) ? (data[0] & 0x80) | 0x40 | S5K83A_FLIP_MASK
|
||||
: (data[0] & 0x80) | S5K83A_FLIP_MASK;
|
||||
err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data[0] = (val) ? 0x0b : 0x0a;
|
||||
err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)
|
||||
{
|
||||
int err;
|
||||
u8 data[1];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
data[0] = 0x05;
|
||||
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
|
||||
*val = (data[0] | 0x80) ? 1 : 0;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)
|
||||
{
|
||||
int err;
|
||||
u8 data[1];
|
||||
struct sd *sd = (struct sd *) gspca_dev;
|
||||
|
||||
data[0] = 0x05;
|
||||
err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = m5602_read_sensor(sd, S5K83A_FLIP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* set or zero seven bit, six is vflip */
|
||||
data[0] = (val) ? (data[0] & 0x40) | 0x80 | S5K83A_FLIP_MASK
|
||||
: (data[0] & 0x40) | S5K83A_FLIP_MASK;
|
||||
err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
data[0] = (val) ? 0x0a : 0x0b;
|
||||
err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int s5k83a_set_led_indication(struct sd *sd, u8 val)
|
||||
{
|
||||
int err = 0;
|
||||
u8 data[1];
|
||||
|
||||
err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (val)
|
||||
data[0] = data[0] | S5K83A_GPIO_LED_MASK;
|
||||
else
|
||||
data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;
|
||||
|
||||
err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);
|
||||
|
||||
return (err < 0) ? err : 0;
|
||||
}
|
||||
|
|
|
@ -21,20 +21,21 @@
|
|||
|
||||
#include "m5602_sensor.h"
|
||||
|
||||
#define S5K83A_FLIP 0x01
|
||||
#define S5K83A_HFLIP_TUNE 0x03
|
||||
#define S5K83A_VFLIP_TUNE 0x05
|
||||
#define S5K83A_WHITENESS 0x0a
|
||||
#define S5K83A_GAIN 0x18
|
||||
#define S5K83A_BRIGHTNESS 0x1b
|
||||
#define S5K83A_PAGE_MAP 0xec
|
||||
#define S5K83A_FLIP 0x01
|
||||
#define S5K83A_HFLIP_TUNE 0x03
|
||||
#define S5K83A_VFLIP_TUNE 0x05
|
||||
#define S5K83A_BRIGHTNESS 0x0a
|
||||
#define S5K83A_EXPOSURE 0x18
|
||||
#define S5K83A_GAIN 0x1b
|
||||
#define S5K83A_PAGE_MAP 0xec
|
||||
|
||||
#define S5K83A_DEFAULT_BRIGHTNESS 0x71
|
||||
#define S5K83A_DEFAULT_WHITENESS 0x7e
|
||||
#define S5K83A_DEFAULT_GAIN 0x00
|
||||
#define S5K83A_MAXIMUM_GAIN 0x3c
|
||||
#define S5K83A_FLIP_MASK 0x10
|
||||
#define S5K83A_DEFAULT_GAIN 0x71
|
||||
#define S5K83A_DEFAULT_BRIGHTNESS 0x7e
|
||||
#define S5K83A_DEFAULT_EXPOSURE 0x00
|
||||
#define S5K83A_MAXIMUM_EXPOSURE 0x3c
|
||||
#define S5K83A_FLIP_MASK 0x10
|
||||
#define S5K83A_GPIO_LED_MASK 0x10
|
||||
#define S5K83A_GPIO_ROTATION_MASK 0x40
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
@ -47,15 +48,14 @@ int s5k83a_init(struct sd *sd);
|
|||
int s5k83a_start(struct sd *sd);
|
||||
int s5k83a_stop(struct sd *sd);
|
||||
int s5k83a_power_down(struct sd *sd);
|
||||
void s5k83a_disconnect(struct sd *sd);
|
||||
|
||||
int s5k83a_set_led_indication(struct sd *sd, u8 val);
|
||||
|
||||
int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int s5k83a_set_whiteness(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int s5k83a_get_whiteness(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);
|
||||
int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
|
||||
|
@ -68,10 +68,18 @@ static const struct m5602_sensor s5k83a = {
|
|||
.start = s5k83a_start,
|
||||
.stop = s5k83a_stop,
|
||||
.power_down = s5k83a_power_down,
|
||||
.disconnect = s5k83a_disconnect,
|
||||
.i2c_slave_id = 0x5a,
|
||||
.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},
|
||||
|
@ -125,7 +133,7 @@ static const unsigned char init_s5k83a[][4] =
|
|||
{SENSOR, 0x01, 0x50, 0x00},
|
||||
{SENSOR, 0x12, 0x20, 0x00},
|
||||
{SENSOR, 0x17, 0x40, 0x00},
|
||||
{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
|
||||
{SENSOR, S5K83A_GAIN, 0x0f, 0x00},
|
||||
{SENSOR, 0x1c, 0x00, 0x00},
|
||||
{SENSOR, 0x02, 0x70, 0x00},
|
||||
{SENSOR, 0x03, 0x0b, 0x00},
|
||||
|
@ -232,7 +240,7 @@ static const unsigned char init_s5k83a[][4] =
|
|||
{SENSOR, 0x01, 0x50, 0x00},
|
||||
{SENSOR, 0x12, 0x20, 0x00},
|
||||
{SENSOR, 0x17, 0x40, 0x00},
|
||||
{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
|
||||
{SENSOR, S5K83A_GAIN, 0x0f, 0x00},
|
||||
{SENSOR, 0x1c, 0x00, 0x00},
|
||||
{SENSOR, 0x02, 0x70, 0x00},
|
||||
/* some values like 0x10 give a blue-purple image */
|
||||
|
@ -320,7 +328,7 @@ static const unsigned char init_s5k83a[][4] =
|
|||
{SENSOR, 0x01, 0x50, 0x00},
|
||||
{SENSOR, 0x12, 0x20, 0x00},
|
||||
{SENSOR, 0x17, 0x40, 0x00},
|
||||
{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00},
|
||||
{SENSOR, S5K83A_GAIN, 0x0f, 0x00},
|
||||
{SENSOR, 0x1c, 0x00, 0x00},
|
||||
{SENSOR, 0x02, 0x70, 0x00},
|
||||
{SENSOR, 0x03, 0x0b, 0x00},
|
||||
|
@ -374,24 +382,23 @@ static const unsigned char init_s5k83a[][4] =
|
|||
(this is value after boot, but after tries can be different) */
|
||||
{SENSOR, 0x00, 0x06, 0x00},
|
||||
|
||||
/* set default brightness */
|
||||
/* set default gain */
|
||||
{SENSOR_LONG, 0x14, 0x00, 0x20},
|
||||
{SENSOR_LONG, 0x0d, 0x01, 0x00},
|
||||
{SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3,
|
||||
S5K83A_DEFAULT_BRIGHTNESS >> 1},
|
||||
{SENSOR_LONG, 0x1b, S5K83A_DEFAULT_GAIN >> 3,
|
||||
S5K83A_DEFAULT_GAIN >> 1},
|
||||
|
||||
/* set default whiteness */
|
||||
{SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00},
|
||||
/* set default brightness */
|
||||
{SENSOR, S5K83A_BRIGHTNESS, S5K83A_DEFAULT_BRIGHTNESS, 0x00},
|
||||
|
||||
/* set default gain */
|
||||
{SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN},
|
||||
/* set default exposure */
|
||||
{SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_EXPOSURE},
|
||||
|
||||
/* set default flip */
|
||||
{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
|
||||
{SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00},
|
||||
{SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00},
|
||||
{SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue