Path: blob/master/drivers/media/video/gspca/m5602/m5602_s5k83a.c
17902 views
/*1* Driver for the s5k83a sensor2*3* Copyright (C) 2008 Erik AndrĂ©n4* Copyright (C) 2007 Ilyes Gouta. Based on the m5603x Linux Driver Project.5* Copyright (C) 2005 m5603x Linux Driver Project <[email protected]>6*7* Portions of code to USB interface and ALi driver software,8* Copyright (c) 2006 Willem Duinker9* v4l2 interface modeled after the V4L2 driver10* for SN9C10x PC Camera Controllers11*12* This program is free software; you can redistribute it and/or13* modify it under the terms of the GNU General Public License as14* published by the Free Software Foundation, version 2.15*16*/1718#include <linux/kthread.h>19#include "m5602_s5k83a.h"2021static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);22static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val);23static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val);24static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);25static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val);26static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);27static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val);28static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val);29static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val);30static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val);3132static struct v4l2_pix_format s5k83a_modes[] = {33{34640,35480,36V4L2_PIX_FMT_SBGGR8,37V4L2_FIELD_NONE,38.sizeimage =39640 * 480,40.bytesperline = 640,41.colorspace = V4L2_COLORSPACE_SRGB,42.priv = 043}44};4546static const struct ctrl s5k83a_ctrls[] = {47#define GAIN_IDX 048{49{50.id = V4L2_CID_GAIN,51.type = V4L2_CTRL_TYPE_INTEGER,52.name = "gain",53.minimum = 0x00,54.maximum = 0xff,55.step = 0x01,56.default_value = S5K83A_DEFAULT_GAIN,57.flags = V4L2_CTRL_FLAG_SLIDER58},59.set = s5k83a_set_gain,60.get = s5k83a_get_gain6162},63#define BRIGHTNESS_IDX 164{65{66.id = V4L2_CID_BRIGHTNESS,67.type = V4L2_CTRL_TYPE_INTEGER,68.name = "brightness",69.minimum = 0x00,70.maximum = 0xff,71.step = 0x01,72.default_value = S5K83A_DEFAULT_BRIGHTNESS,73.flags = V4L2_CTRL_FLAG_SLIDER74},75.set = s5k83a_set_brightness,76.get = s5k83a_get_brightness,77},78#define EXPOSURE_IDX 279{80{81.id = V4L2_CID_EXPOSURE,82.type = V4L2_CTRL_TYPE_INTEGER,83.name = "exposure",84.minimum = 0x00,85.maximum = S5K83A_MAXIMUM_EXPOSURE,86.step = 0x01,87.default_value = S5K83A_DEFAULT_EXPOSURE,88.flags = V4L2_CTRL_FLAG_SLIDER89},90.set = s5k83a_set_exposure,91.get = s5k83a_get_exposure92},93#define HFLIP_IDX 394{95{96.id = V4L2_CID_HFLIP,97.type = V4L2_CTRL_TYPE_BOOLEAN,98.name = "horizontal flip",99.minimum = 0,100.maximum = 1,101.step = 1,102.default_value = 0103},104.set = s5k83a_set_hflip,105.get = s5k83a_get_hflip106},107#define VFLIP_IDX 4108{109{110.id = V4L2_CID_VFLIP,111.type = V4L2_CTRL_TYPE_BOOLEAN,112.name = "vertical flip",113.minimum = 0,114.maximum = 1,115.step = 1,116.default_value = 0117},118.set = s5k83a_set_vflip,119.get = s5k83a_get_vflip120}121};122123static void s5k83a_dump_registers(struct sd *sd);124static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data);125static int s5k83a_set_led_indication(struct sd *sd, u8 val);126static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,127__s32 vflip, __s32 hflip);128129int s5k83a_probe(struct sd *sd)130{131struct s5k83a_priv *sens_priv;132u8 prod_id = 0, ver_id = 0;133int i, err = 0;134135if (force_sensor) {136if (force_sensor == S5K83A_SENSOR) {137info("Forcing a %s sensor", s5k83a.name);138goto sensor_found;139}140/* If we want to force another sensor, don't try to probe this141* one */142return -ENODEV;143}144145PDEBUG(D_PROBE, "Probing for a s5k83a sensor");146147/* Preinit the sensor */148for (i = 0; i < ARRAY_SIZE(preinit_s5k83a) && !err; i++) {149u8 data[2] = {preinit_s5k83a[i][2], preinit_s5k83a[i][3]};150if (preinit_s5k83a[i][0] == SENSOR)151err = m5602_write_sensor(sd, preinit_s5k83a[i][1],152data, 2);153else154err = m5602_write_bridge(sd, preinit_s5k83a[i][1],155data[0]);156}157158/* We don't know what register (if any) that contain the product id159* Just pick the first addresses that seem to produce the same results160* on multiple machines */161if (m5602_read_sensor(sd, 0x00, &prod_id, 1))162return -ENODEV;163164if (m5602_read_sensor(sd, 0x01, &ver_id, 1))165return -ENODEV;166167if ((prod_id == 0xff) || (ver_id == 0xff))168return -ENODEV;169else170info("Detected a s5k83a sensor");171172sensor_found:173sens_priv = kmalloc(174sizeof(struct s5k83a_priv), GFP_KERNEL);175if (!sens_priv)176return -ENOMEM;177178sens_priv->settings =179kmalloc(sizeof(s32)*ARRAY_SIZE(s5k83a_ctrls), GFP_KERNEL);180if (!sens_priv->settings) {181kfree(sens_priv);182return -ENOMEM;183}184185sd->gspca_dev.cam.cam_mode = s5k83a_modes;186sd->gspca_dev.cam.nmodes = ARRAY_SIZE(s5k83a_modes);187sd->desc->ctrls = s5k83a_ctrls;188sd->desc->nctrls = ARRAY_SIZE(s5k83a_ctrls);189190/* null the pointer! thread is't running now */191sens_priv->rotation_thread = NULL;192193for (i = 0; i < ARRAY_SIZE(s5k83a_ctrls); i++)194sens_priv->settings[i] = s5k83a_ctrls[i].qctrl.default_value;195196sd->sensor_priv = sens_priv;197return 0;198}199200int s5k83a_init(struct sd *sd)201{202int i, err = 0;203s32 *sensor_settings =204((struct s5k83a_priv *) sd->sensor_priv)->settings;205206for (i = 0; i < ARRAY_SIZE(init_s5k83a) && !err; i++) {207u8 data[2] = {0x00, 0x00};208209switch (init_s5k83a[i][0]) {210case BRIDGE:211err = m5602_write_bridge(sd,212init_s5k83a[i][1],213init_s5k83a[i][2]);214break;215216case SENSOR:217data[0] = init_s5k83a[i][2];218err = m5602_write_sensor(sd,219init_s5k83a[i][1], data, 1);220break;221222case SENSOR_LONG:223data[0] = init_s5k83a[i][2];224data[1] = init_s5k83a[i][3];225err = m5602_write_sensor(sd,226init_s5k83a[i][1], data, 2);227break;228default:229info("Invalid stream command, exiting init");230return -EINVAL;231}232}233234if (dump_sensor)235s5k83a_dump_registers(sd);236237err = s5k83a_set_gain(&sd->gspca_dev, sensor_settings[GAIN_IDX]);238if (err < 0)239return err;240241err = s5k83a_set_brightness(&sd->gspca_dev,242sensor_settings[BRIGHTNESS_IDX]);243if (err < 0)244return err;245246err = s5k83a_set_exposure(&sd->gspca_dev,247sensor_settings[EXPOSURE_IDX]);248if (err < 0)249return err;250251err = s5k83a_set_hflip(&sd->gspca_dev, sensor_settings[HFLIP_IDX]);252if (err < 0)253return err;254255err = s5k83a_set_vflip(&sd->gspca_dev, sensor_settings[VFLIP_IDX]);256257return err;258}259260static int rotation_thread_function(void *data)261{262struct sd *sd = (struct sd *) data;263struct s5k83a_priv *sens_priv = sd->sensor_priv;264u8 reg, previous_rotation = 0;265__s32 vflip, hflip;266267set_current_state(TASK_INTERRUPTIBLE);268while (!schedule_timeout(100)) {269if (mutex_lock_interruptible(&sd->gspca_dev.usb_lock))270break;271272s5k83a_get_rotation(sd, ®);273if (previous_rotation != reg) {274previous_rotation = reg;275info("Camera was flipped");276277s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);278s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);279280if (reg) {281vflip = !vflip;282hflip = !hflip;283}284s5k83a_set_flip_real((struct gspca_dev *) sd,285vflip, hflip);286}287288mutex_unlock(&sd->gspca_dev.usb_lock);289set_current_state(TASK_INTERRUPTIBLE);290}291292/* return to "front" flip */293if (previous_rotation) {294s5k83a_get_vflip((struct gspca_dev *) sd, &vflip);295s5k83a_get_hflip((struct gspca_dev *) sd, &hflip);296s5k83a_set_flip_real((struct gspca_dev *) sd, vflip, hflip);297}298299sens_priv->rotation_thread = NULL;300return 0;301}302303int s5k83a_start(struct sd *sd)304{305int i, err = 0;306struct s5k83a_priv *sens_priv = sd->sensor_priv;307308/* Create another thread, polling the GPIO ports of the camera to check309if it got rotated. This is how the windows driver does it so we have310to assume that there is no better way of accomplishing this */311sens_priv->rotation_thread = kthread_create(rotation_thread_function,312sd, "rotation thread");313wake_up_process(sens_priv->rotation_thread);314315/* Preinit the sensor */316for (i = 0; i < ARRAY_SIZE(start_s5k83a) && !err; i++) {317u8 data[2] = {start_s5k83a[i][2], start_s5k83a[i][3]};318if (start_s5k83a[i][0] == SENSOR)319err = m5602_write_sensor(sd, start_s5k83a[i][1],320data, 2);321else322err = m5602_write_bridge(sd, start_s5k83a[i][1],323data[0]);324}325if (err < 0)326return err;327328return s5k83a_set_led_indication(sd, 1);329}330331int s5k83a_stop(struct sd *sd)332{333struct s5k83a_priv *sens_priv = sd->sensor_priv;334335if (sens_priv->rotation_thread)336kthread_stop(sens_priv->rotation_thread);337338return s5k83a_set_led_indication(sd, 0);339}340341void s5k83a_disconnect(struct sd *sd)342{343struct s5k83a_priv *sens_priv = sd->sensor_priv;344345s5k83a_stop(sd);346347sd->sensor = NULL;348kfree(sens_priv->settings);349kfree(sens_priv);350}351352static int s5k83a_get_gain(struct gspca_dev *gspca_dev, __s32 *val)353{354struct sd *sd = (struct sd *) gspca_dev;355struct s5k83a_priv *sens_priv = sd->sensor_priv;356357*val = sens_priv->settings[GAIN_IDX];358return 0;359}360361static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val)362{363int err;364u8 data[2];365struct sd *sd = (struct sd *) gspca_dev;366struct s5k83a_priv *sens_priv = sd->sensor_priv;367368sens_priv->settings[GAIN_IDX] = val;369370data[0] = 0x00;371data[1] = 0x20;372err = m5602_write_sensor(sd, 0x14, data, 2);373if (err < 0)374return err;375376data[0] = 0x01;377data[1] = 0x00;378err = m5602_write_sensor(sd, 0x0d, data, 2);379if (err < 0)380return err;381382/* FIXME: This is not sane, we need to figure out the composition383of these registers */384data[0] = val >> 3; /* gain, high 5 bits */385data[1] = val >> 1; /* gain, high 7 bits */386err = m5602_write_sensor(sd, S5K83A_GAIN, data, 2);387388return err;389}390391static int s5k83a_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)392{393struct sd *sd = (struct sd *) gspca_dev;394struct s5k83a_priv *sens_priv = sd->sensor_priv;395396*val = sens_priv->settings[BRIGHTNESS_IDX];397return 0;398}399400static int s5k83a_set_brightness(struct gspca_dev *gspca_dev, __s32 val)401{402int err;403u8 data[1];404struct sd *sd = (struct sd *) gspca_dev;405struct s5k83a_priv *sens_priv = sd->sensor_priv;406407sens_priv->settings[BRIGHTNESS_IDX] = val;408data[0] = val;409err = m5602_write_sensor(sd, S5K83A_BRIGHTNESS, data, 1);410return err;411}412413static int s5k83a_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)414{415struct sd *sd = (struct sd *) gspca_dev;416struct s5k83a_priv *sens_priv = sd->sensor_priv;417418*val = sens_priv->settings[EXPOSURE_IDX];419return 0;420}421422static int s5k83a_set_exposure(struct gspca_dev *gspca_dev, __s32 val)423{424int err;425u8 data[2];426struct sd *sd = (struct sd *) gspca_dev;427struct s5k83a_priv *sens_priv = sd->sensor_priv;428429sens_priv->settings[EXPOSURE_IDX] = val;430data[0] = 0;431data[1] = val;432err = m5602_write_sensor(sd, S5K83A_EXPOSURE, data, 2);433return err;434}435436static int s5k83a_get_vflip(struct gspca_dev *gspca_dev, __s32 *val)437{438struct sd *sd = (struct sd *) gspca_dev;439struct s5k83a_priv *sens_priv = sd->sensor_priv;440441*val = sens_priv->settings[VFLIP_IDX];442return 0;443}444445static int s5k83a_set_flip_real(struct gspca_dev *gspca_dev,446__s32 vflip, __s32 hflip)447{448int err;449u8 data[1];450struct sd *sd = (struct sd *) gspca_dev;451452data[0] = 0x05;453err = m5602_write_sensor(sd, S5K83A_PAGE_MAP, data, 1);454if (err < 0)455return err;456457/* six bit is vflip, seven is hflip */458data[0] = S5K83A_FLIP_MASK;459data[0] = (vflip) ? data[0] | 0x40 : data[0];460data[0] = (hflip) ? data[0] | 0x80 : data[0];461462err = m5602_write_sensor(sd, S5K83A_FLIP, data, 1);463if (err < 0)464return err;465466data[0] = (vflip) ? 0x0b : 0x0a;467err = m5602_write_sensor(sd, S5K83A_VFLIP_TUNE, data, 1);468if (err < 0)469return err;470471data[0] = (hflip) ? 0x0a : 0x0b;472err = m5602_write_sensor(sd, S5K83A_HFLIP_TUNE, data, 1);473return err;474}475476static int s5k83a_set_vflip(struct gspca_dev *gspca_dev, __s32 val)477{478int err;479u8 reg;480__s32 hflip;481struct sd *sd = (struct sd *) gspca_dev;482struct s5k83a_priv *sens_priv = sd->sensor_priv;483484sens_priv->settings[VFLIP_IDX] = val;485486s5k83a_get_hflip(gspca_dev, &hflip);487488err = s5k83a_get_rotation(sd, ®);489if (err < 0)490return err;491if (reg) {492val = !val;493hflip = !hflip;494}495496err = s5k83a_set_flip_real(gspca_dev, val, hflip);497return err;498}499500static int s5k83a_get_hflip(struct gspca_dev *gspca_dev, __s32 *val)501{502struct sd *sd = (struct sd *) gspca_dev;503struct s5k83a_priv *sens_priv = sd->sensor_priv;504505*val = sens_priv->settings[HFLIP_IDX];506return 0;507}508509static int s5k83a_set_hflip(struct gspca_dev *gspca_dev, __s32 val)510{511int err;512u8 reg;513__s32 vflip;514struct sd *sd = (struct sd *) gspca_dev;515struct s5k83a_priv *sens_priv = sd->sensor_priv;516517sens_priv->settings[HFLIP_IDX] = val;518519s5k83a_get_vflip(gspca_dev, &vflip);520521err = s5k83a_get_rotation(sd, ®);522if (err < 0)523return err;524if (reg) {525val = !val;526vflip = !vflip;527}528529err = s5k83a_set_flip_real(gspca_dev, vflip, val);530return err;531}532533static int s5k83a_set_led_indication(struct sd *sd, u8 val)534{535int err = 0;536u8 data[1];537538err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, data);539if (err < 0)540return err;541542if (val)543data[0] = data[0] | S5K83A_GPIO_LED_MASK;544else545data[0] = data[0] & ~S5K83A_GPIO_LED_MASK;546547err = m5602_write_bridge(sd, M5602_XB_GPIO_DAT, data[0]);548549return err;550}551552/* Get camera rotation on Acer notebooks */553static int s5k83a_get_rotation(struct sd *sd, u8 *reg_data)554{555int err = m5602_read_bridge(sd, M5602_XB_GPIO_DAT, reg_data);556*reg_data = (*reg_data & S5K83A_GPIO_ROTATION_MASK) ? 0 : 1;557return err;558}559560static void s5k83a_dump_registers(struct sd *sd)561{562int address;563u8 page, old_page;564m5602_read_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);565566for (page = 0; page < 16; page++) {567m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);568info("Dumping the s5k83a register state for page 0x%x", page);569for (address = 0; address <= 0xff; address++) {570u8 val = 0;571m5602_read_sensor(sd, address, &val, 1);572info("register 0x%x contains 0x%x",573address, val);574}575}576info("s5k83a register state dump complete");577578for (page = 0; page < 16; page++) {579m5602_write_sensor(sd, S5K83A_PAGE_MAP, &page, 1);580info("Probing for which registers that are read/write "581"for page 0x%x", page);582for (address = 0; address <= 0xff; address++) {583u8 old_val, ctrl_val, test_val = 0xff;584585m5602_read_sensor(sd, address, &old_val, 1);586m5602_write_sensor(sd, address, &test_val, 1);587m5602_read_sensor(sd, address, &ctrl_val, 1);588589if (ctrl_val == test_val)590info("register 0x%x is writeable", address);591else592info("register 0x%x is read only", address);593594/* Restore original val */595m5602_write_sensor(sd, address, &old_val, 1);596}597}598info("Read/write register probing complete");599m5602_write_sensor(sd, S5K83A_PAGE_MAP, &old_page, 1);600}601602603