Commit ac3d5bfe authored by Luk?? Karas's avatar Luk?? Karas Committed by Mauro Carvalho Chehab

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: default avatarLuk?? Karas <lukas.karas@centrum.cz>
Signed-off-by: default avatarErik Andr?n <erik.andren@gmail.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 04f15655
...@@ -80,6 +80,16 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data) ...@@ -80,6 +80,16 @@ int m5602_write_bridge(struct sd *sd, u8 address, u8 i2c_data)
return (err < 0) ? err : 0; 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, int m5602_read_sensor(struct sd *sd, const u8 address,
u8 *i2c_data, const u8 len) u8 *i2c_data, const u8 len)
{ {
...@@ -88,9 +98,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address, ...@@ -88,9 +98,7 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
if (!len || len > sd->sensor->i2c_regW) if (!len || len > sd->sensor->i2c_regW)
return -EINVAL; return -EINVAL;
do { err = m5602_wait_for_i2c(sd);
err = m5602_read_bridge(sd, M5602_XB_I2C_STATUS, i2c_data);
} while ((*i2c_data & I2C_BUSY) && !err);
if (err < 0) if (err < 0)
return err; return err;
...@@ -118,6 +126,10 @@ int m5602_read_sensor(struct sd *sd, const u8 address, ...@@ -118,6 +126,10 @@ int m5602_read_sensor(struct sd *sd, const u8 address,
} }
for (i = 0; (i < len) && !err; i++) { 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])); err = m5602_read_bridge(sd, M5602_XB_I2C_DATA, &(i2c_data[i]));
PDEBUG(D_CONF, "Reading sensor register " PDEBUG(D_CONF, "Reading sensor register "
......
...@@ -24,17 +24,18 @@ ...@@ -24,17 +24,18 @@
#define S5K83A_FLIP 0x01 #define S5K83A_FLIP 0x01
#define S5K83A_HFLIP_TUNE 0x03 #define S5K83A_HFLIP_TUNE 0x03
#define S5K83A_VFLIP_TUNE 0x05 #define S5K83A_VFLIP_TUNE 0x05
#define S5K83A_WHITENESS 0x0a #define S5K83A_BRIGHTNESS 0x0a
#define S5K83A_GAIN 0x18 #define S5K83A_EXPOSURE 0x18
#define S5K83A_BRIGHTNESS 0x1b #define S5K83A_GAIN 0x1b
#define S5K83A_PAGE_MAP 0xec #define S5K83A_PAGE_MAP 0xec
#define S5K83A_DEFAULT_BRIGHTNESS 0x71 #define S5K83A_DEFAULT_GAIN 0x71
#define S5K83A_DEFAULT_WHITENESS 0x7e #define S5K83A_DEFAULT_BRIGHTNESS 0x7e
#define S5K83A_DEFAULT_GAIN 0x00 #define S5K83A_DEFAULT_EXPOSURE 0x00
#define S5K83A_MAXIMUM_GAIN 0x3c #define S5K83A_MAXIMUM_EXPOSURE 0x3c
#define S5K83A_FLIP_MASK 0x10 #define S5K83A_FLIP_MASK 0x10
#define S5K83A_GPIO_LED_MASK 0x10 #define S5K83A_GPIO_LED_MASK 0x10
#define S5K83A_GPIO_ROTATION_MASK 0x40
/*****************************************************************************/ /*****************************************************************************/
...@@ -47,15 +48,14 @@ int s5k83a_init(struct sd *sd); ...@@ -47,15 +48,14 @@ int s5k83a_init(struct sd *sd);
int s5k83a_start(struct sd *sd); int s5k83a_start(struct sd *sd);
int s5k83a_stop(struct sd *sd); int s5k83a_stop(struct sd *sd);
int s5k83a_power_down(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_set_gain(struct gspca_dev *gspca_dev, __s32 val);
int s5k83a_get_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_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);
int s5k83a_set_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); int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);
...@@ -68,10 +68,18 @@ static const struct m5602_sensor s5k83a = { ...@@ -68,10 +68,18 @@ static const struct m5602_sensor s5k83a = {
.start = s5k83a_start, .start = s5k83a_start,
.stop = s5k83a_stop, .stop = s5k83a_stop,
.power_down = s5k83a_power_down, .power_down = s5k83a_power_down,
.disconnect = s5k83a_disconnect,
.i2c_slave_id = 0x5a, .i2c_slave_id = 0x5a,
.i2c_regW = 2, .i2c_regW = 2,
}; };
struct s5k83a_priv {
/* We use another thread periodically
probing the orientation of the camera */
struct task_struct *rotation_thread;
s32 *settings;
};
static const unsigned char preinit_s5k83a[][4] = static const unsigned char preinit_s5k83a[][4] =
{ {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00}, {BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
...@@ -125,7 +133,7 @@ static const unsigned char init_s5k83a[][4] = ...@@ -125,7 +133,7 @@ static const unsigned char init_s5k83a[][4] =
{SENSOR, 0x01, 0x50, 0x00}, {SENSOR, 0x01, 0x50, 0x00},
{SENSOR, 0x12, 0x20, 0x00}, {SENSOR, 0x12, 0x20, 0x00},
{SENSOR, 0x17, 0x40, 0x00}, {SENSOR, 0x17, 0x40, 0x00},
{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, {SENSOR, S5K83A_GAIN, 0x0f, 0x00},
{SENSOR, 0x1c, 0x00, 0x00}, {SENSOR, 0x1c, 0x00, 0x00},
{SENSOR, 0x02, 0x70, 0x00}, {SENSOR, 0x02, 0x70, 0x00},
{SENSOR, 0x03, 0x0b, 0x00}, {SENSOR, 0x03, 0x0b, 0x00},
...@@ -232,7 +240,7 @@ static const unsigned char init_s5k83a[][4] = ...@@ -232,7 +240,7 @@ static const unsigned char init_s5k83a[][4] =
{SENSOR, 0x01, 0x50, 0x00}, {SENSOR, 0x01, 0x50, 0x00},
{SENSOR, 0x12, 0x20, 0x00}, {SENSOR, 0x12, 0x20, 0x00},
{SENSOR, 0x17, 0x40, 0x00}, {SENSOR, 0x17, 0x40, 0x00},
{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, {SENSOR, S5K83A_GAIN, 0x0f, 0x00},
{SENSOR, 0x1c, 0x00, 0x00}, {SENSOR, 0x1c, 0x00, 0x00},
{SENSOR, 0x02, 0x70, 0x00}, {SENSOR, 0x02, 0x70, 0x00},
/* some values like 0x10 give a blue-purple image */ /* some values like 0x10 give a blue-purple image */
...@@ -320,7 +328,7 @@ static const unsigned char init_s5k83a[][4] = ...@@ -320,7 +328,7 @@ static const unsigned char init_s5k83a[][4] =
{SENSOR, 0x01, 0x50, 0x00}, {SENSOR, 0x01, 0x50, 0x00},
{SENSOR, 0x12, 0x20, 0x00}, {SENSOR, 0x12, 0x20, 0x00},
{SENSOR, 0x17, 0x40, 0x00}, {SENSOR, 0x17, 0x40, 0x00},
{SENSOR, S5K83A_BRIGHTNESS, 0x0f, 0x00}, {SENSOR, S5K83A_GAIN, 0x0f, 0x00},
{SENSOR, 0x1c, 0x00, 0x00}, {SENSOR, 0x1c, 0x00, 0x00},
{SENSOR, 0x02, 0x70, 0x00}, {SENSOR, 0x02, 0x70, 0x00},
{SENSOR, 0x03, 0x0b, 0x00}, {SENSOR, 0x03, 0x0b, 0x00},
...@@ -374,24 +382,23 @@ static const unsigned char init_s5k83a[][4] = ...@@ -374,24 +382,23 @@ static const unsigned char init_s5k83a[][4] =
(this is value after boot, but after tries can be different) */ (this is value after boot, but after tries can be different) */
{SENSOR, 0x00, 0x06, 0x00}, {SENSOR, 0x00, 0x06, 0x00},
/* set default brightness */ /* set default gain */
{SENSOR_LONG, 0x14, 0x00, 0x20}, {SENSOR_LONG, 0x14, 0x00, 0x20},
{SENSOR_LONG, 0x0d, 0x01, 0x00}, {SENSOR_LONG, 0x0d, 0x01, 0x00},
{SENSOR_LONG, 0x1b, S5K83A_DEFAULT_BRIGHTNESS >> 3, {SENSOR_LONG, 0x1b, S5K83A_DEFAULT_GAIN >> 3,
S5K83A_DEFAULT_BRIGHTNESS >> 1}, S5K83A_DEFAULT_GAIN >> 1},
/* set default whiteness */ /* set default brightness */
{SENSOR, S5K83A_WHITENESS, S5K83A_DEFAULT_WHITENESS, 0x00}, {SENSOR, S5K83A_BRIGHTNESS, S5K83A_DEFAULT_BRIGHTNESS, 0x00},
/* set default gain */ /* set default exposure */
{SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_GAIN}, {SENSOR_LONG, 0x18, 0x00, S5K83A_DEFAULT_EXPOSURE},
/* set default flip */ /* set default flip */
{SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00}, {SENSOR, S5K83A_PAGE_MAP, 0x05, 0x00},
{SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00}, {SENSOR, S5K83A_FLIP, 0x00 | S5K83A_FLIP_MASK, 0x00},
{SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00}, {SENSOR, S5K83A_HFLIP_TUNE, 0x0b, 0x00},
{SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00} {SENSOR, S5K83A_VFLIP_TUNE, 0x0a, 0x00}
}; };
#endif #endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment