alistair23-linux/drivers/staging/dream/camera/mt9d112.c
Tejun Heo 5a0e3ad6af include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit slab.h inclusion from percpu.h
percpu.h is included by sched.h and module.h and thus ends up being
included when building most .c files.  percpu.h includes slab.h which
in turn includes gfp.h making everything defined by the two files
universally available and complicating inclusion dependencies.

percpu.h -> slab.h dependency is about to be removed.  Prepare for
this change by updating users of gfp and slab facilities include those
headers directly instead of assuming availability.  As this conversion
needs to touch large number of source files, the following script is
used as the basis of conversion.

  http://userweb.kernel.org/~tj/misc/slabh-sweep.py

The script does the followings.

* Scan files for gfp and slab usages and update includes such that
  only the necessary includes are there.  ie. if only gfp is used,
  gfp.h, if slab is used, slab.h.

* When the script inserts a new include, it looks at the include
  blocks and try to put the new include such that its order conforms
  to its surrounding.  It's put in the include block which contains
  core kernel includes, in the same order that the rest are ordered -
  alphabetical, Christmas tree, rev-Xmas-tree or at the end if there
  doesn't seem to be any matching order.

* If the script can't find a place to put a new include (mostly
  because the file doesn't have fitting include block), it prints out
  an error message indicating which .h file needs to be added to the
  file.

The conversion was done in the following steps.

1. The initial automatic conversion of all .c files updated slightly
   over 4000 files, deleting around 700 includes and adding ~480 gfp.h
   and ~3000 slab.h inclusions.  The script emitted errors for ~400
   files.

2. Each error was manually checked.  Some didn't need the inclusion,
   some needed manual addition while adding it to implementation .h or
   embedding .c file was more appropriate for others.  This step added
   inclusions to around 150 files.

3. The script was run again and the output was compared to the edits
   from #2 to make sure no file was left behind.

4. Several build tests were done and a couple of problems were fixed.
   e.g. lib/decompress_*.c used malloc/free() wrappers around slab
   APIs requiring slab.h to be added manually.

5. The script was run on all .h files but without automatically
   editing them as sprinkling gfp.h and slab.h inclusions around .h
   files could easily lead to inclusion dependency hell.  Most gfp.h
   inclusion directives were ignored as stuff from gfp.h was usually
   wildly available and often used in preprocessor macros.  Each
   slab.h inclusion directive was examined and added manually as
   necessary.

6. percpu.h was updated not to include slab.h.

7. Build test were done on the following configurations and failures
   were fixed.  CONFIG_GCOV_KERNEL was turned off for all tests (as my
   distributed build env didn't work with gcov compiles) and a few
   more options had to be turned off depending on archs to make things
   build (like ipr on powerpc/64 which failed due to missing writeq).

   * x86 and x86_64 UP and SMP allmodconfig and a custom test config.
   * powerpc and powerpc64 SMP allmodconfig
   * sparc and sparc64 SMP allmodconfig
   * ia64 SMP allmodconfig
   * s390 SMP allmodconfig
   * alpha SMP allmodconfig
   * um on x86_64 SMP allmodconfig

8. percpu.h modifications were reverted so that it could be applied as
   a separate patch and serve as bisection point.

Given the fact that I had only a couple of failures from tests on step
6, I'm fairly confident about the coverage of this conversion patch.
If there is a breakage, it's likely to be something in one of the arch
headers which should be easily discoverable easily on most builds of
the specific arch.

Signed-off-by: Tejun Heo <tj@kernel.org>
Guess-its-ok-by: Christoph Lameter <cl@linux-foundation.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Lee Schermerhorn <Lee.Schermerhorn@hp.com>
2010-03-30 22:02:32 +09:00

763 lines
14 KiB
C

/*
* Copyright (C) 2008-2009 QUALCOMM Incorporated.
*/
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/i2c.h>
#include <linux/uaccess.h>
#include <linux/miscdevice.h>
#include <media/msm_camera.h>
#include <mach/gpio.h>
#include "mt9d112.h"
/* Micron MT9D112 Registers and their values */
/* Sensor Core Registers */
#define REG_MT9D112_MODEL_ID 0x3000
#define MT9D112_MODEL_ID 0x1580
/* SOC Registers Page 1 */
#define REG_MT9D112_SENSOR_RESET 0x301A
#define REG_MT9D112_STANDBY_CONTROL 0x3202
#define REG_MT9D112_MCU_BOOT 0x3386
struct mt9d112_work {
struct work_struct work;
};
static struct mt9d112_work *mt9d112_sensorw;
static struct i2c_client *mt9d112_client;
struct mt9d112_ctrl {
const struct msm_camera_sensor_info *sensordata;
};
static struct mt9d112_ctrl *mt9d112_ctrl;
static DECLARE_WAIT_QUEUE_HEAD(mt9d112_wait_queue);
DECLARE_MUTEX(mt9d112_sem);
/*=============================================================
EXTERNAL DECLARATIONS
==============================================================*/
extern struct mt9d112_reg mt9d112_regs;
/*=============================================================*/
static int mt9d112_reset(const struct msm_camera_sensor_info *dev)
{
int rc = 0;
rc = gpio_request(dev->sensor_reset, "mt9d112");
if (!rc) {
rc = gpio_direction_output(dev->sensor_reset, 0);
mdelay(20);
rc = gpio_direction_output(dev->sensor_reset, 1);
}
gpio_free(dev->sensor_reset);
return rc;
}
static int32_t mt9d112_i2c_txdata(unsigned short saddr,
unsigned char *txdata, int length)
{
struct i2c_msg msg[] = {
{
.addr = saddr,
.flags = 0,
.len = length,
.buf = txdata,
},
};
if (i2c_transfer(mt9d112_client->adapter, msg, 1) < 0) {
CDBG("mt9d112_i2c_txdata failed\n");
return -EIO;
}
return 0;
}
static int32_t mt9d112_i2c_write(unsigned short saddr,
unsigned short waddr, unsigned short wdata, enum mt9d112_width width)
{
int32_t rc = -EIO;
unsigned char buf[4];
memset(buf, 0, sizeof(buf));
switch (width) {
case WORD_LEN: {
buf[0] = (waddr & 0xFF00)>>8;
buf[1] = (waddr & 0x00FF);
buf[2] = (wdata & 0xFF00)>>8;
buf[3] = (wdata & 0x00FF);
rc = mt9d112_i2c_txdata(saddr, buf, 4);
}
break;
case BYTE_LEN: {
buf[0] = waddr;
buf[1] = wdata;
rc = mt9d112_i2c_txdata(saddr, buf, 2);
}
break;
default:
break;
}
if (rc < 0)
CDBG(
"i2c_write failed, addr = 0x%x, val = 0x%x!\n",
waddr, wdata);
return rc;
}
static int32_t mt9d112_i2c_write_table(
struct mt9d112_i2c_reg_conf const *reg_conf_tbl,
int num_of_items_in_table)
{
int i;
int32_t rc = -EIO;
for (i = 0; i < num_of_items_in_table; i++) {
rc = mt9d112_i2c_write(mt9d112_client->addr,
reg_conf_tbl->waddr, reg_conf_tbl->wdata,
reg_conf_tbl->width);
if (rc < 0)
break;
if (reg_conf_tbl->mdelay_time != 0)
mdelay(reg_conf_tbl->mdelay_time);
reg_conf_tbl++;
}
return rc;
}
static int mt9d112_i2c_rxdata(unsigned short saddr,
unsigned char *rxdata, int length)
{
struct i2c_msg msgs[] = {
{
.addr = saddr,
.flags = 0,
.len = 2,
.buf = rxdata,
},
{
.addr = saddr,
.flags = I2C_M_RD,
.len = length,
.buf = rxdata,
},
};
if (i2c_transfer(mt9d112_client->adapter, msgs, 2) < 0) {
CDBG("mt9d112_i2c_rxdata failed!\n");
return -EIO;
}
return 0;
}
static int32_t mt9d112_i2c_read(unsigned short saddr,
unsigned short raddr, unsigned short *rdata, enum mt9d112_width width)
{
int32_t rc = 0;
unsigned char buf[4];
if (!rdata)
return -EIO;
memset(buf, 0, sizeof(buf));
switch (width) {
case WORD_LEN: {
buf[0] = (raddr & 0xFF00)>>8;
buf[1] = (raddr & 0x00FF);
rc = mt9d112_i2c_rxdata(saddr, buf, 2);
if (rc < 0)
return rc;
*rdata = buf[0] << 8 | buf[1];
}
break;
default:
break;
}
if (rc < 0)
CDBG("mt9d112_i2c_read failed!\n");
return rc;
}
static int32_t mt9d112_set_lens_roll_off(void)
{
int32_t rc = 0;
rc = mt9d112_i2c_write_table(&mt9d112_regs.rftbl[0],
mt9d112_regs.rftbl_size);
return rc;
}
static long mt9d112_reg_init(void)
{
int32_t array_length;
int32_t i;
long rc;
/* PLL Setup Start */
rc = mt9d112_i2c_write_table(&mt9d112_regs.plltbl[0],
mt9d112_regs.plltbl_size);
if (rc < 0)
return rc;
/* PLL Setup End */
array_length = mt9d112_regs.prev_snap_reg_settings_size;
/* Configure sensor for Preview mode and Snapshot mode */
for (i = 0; i < array_length; i++) {
rc = mt9d112_i2c_write(mt9d112_client->addr,
mt9d112_regs.prev_snap_reg_settings[i].register_address,
mt9d112_regs.prev_snap_reg_settings[i].register_value,
WORD_LEN);
if (rc < 0)
return rc;
}
/* Configure for Noise Reduction, Saturation and Aperture Correction */
array_length = mt9d112_regs.noise_reduction_reg_settings_size;
for (i = 0; i < array_length; i++) {
rc = mt9d112_i2c_write(mt9d112_client->addr,
mt9d112_regs.noise_reduction_reg_settings[i].register_address,
mt9d112_regs.noise_reduction_reg_settings[i].register_value,
WORD_LEN);
if (rc < 0)
return rc;
}
/* Set Color Kill Saturation point to optimum value */
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x35A4,
0x0593,
WORD_LEN);
if (rc < 0)
return rc;
rc = mt9d112_i2c_write_table(&mt9d112_regs.stbl[0],
mt9d112_regs.stbl_size);
if (rc < 0)
return rc;
rc = mt9d112_set_lens_roll_off();
if (rc < 0)
return rc;
return 0;
}
static long mt9d112_set_sensor_mode(int mode)
{
uint16_t clock;
long rc = 0;
switch (mode) {
case SENSOR_PREVIEW_MODE:
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x338C, 0xA20C, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x3390, 0x0004, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x338C, 0xA215, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x3390, 0x0004, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x338C, 0xA20B, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x3390, 0x0000, WORD_LEN);
if (rc < 0)
return rc;
clock = 0x0250;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x341C, clock, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x338C, 0xA103, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x3390, 0x0001, WORD_LEN);
if (rc < 0)
return rc;
mdelay(5);
break;
case SENSOR_SNAPSHOT_MODE:
/* Switch to lower fps for Snapshot */
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x341C, 0x0120, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x338C, 0xA120, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x3390, 0x0002, WORD_LEN);
if (rc < 0)
return rc;
mdelay(5);
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x338C, 0xA103, WORD_LEN);
if (rc < 0)
return rc;
rc =
mt9d112_i2c_write(mt9d112_client->addr,
0x3390, 0x0002, WORD_LEN);
if (rc < 0)
return rc;
break;
default:
return -EINVAL;
}
return 0;
}
static long mt9d112_set_effect(int mode, int effect)
{
uint16_t reg_addr;
uint16_t reg_val;
long rc = 0;
switch (mode) {
case SENSOR_PREVIEW_MODE:
/* Context A Special Effects */
reg_addr = 0x2799;
break;
case SENSOR_SNAPSHOT_MODE:
/* Context B Special Effects */
reg_addr = 0x279B;
break;
default:
reg_addr = 0x2799;
break;
}
switch (effect) {
case CAMERA_EFFECT_OFF: {
reg_val = 0x6440;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x338C, reg_addr, WORD_LEN);
if (rc < 0)
return rc;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x3390, reg_val, WORD_LEN);
if (rc < 0)
return rc;
}
break;
case CAMERA_EFFECT_MONO: {
reg_val = 0x6441;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x338C, reg_addr, WORD_LEN);
if (rc < 0)
return rc;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x3390, reg_val, WORD_LEN);
if (rc < 0)
return rc;
}
break;
case CAMERA_EFFECT_NEGATIVE: {
reg_val = 0x6443;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x338C, reg_addr, WORD_LEN);
if (rc < 0)
return rc;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x3390, reg_val, WORD_LEN);
if (rc < 0)
return rc;
}
break;
case CAMERA_EFFECT_SOLARIZE: {
reg_val = 0x6445;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x338C, reg_addr, WORD_LEN);
if (rc < 0)
return rc;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x3390, reg_val, WORD_LEN);
if (rc < 0)
return rc;
}
break;
case CAMERA_EFFECT_SEPIA: {
reg_val = 0x6442;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x338C, reg_addr, WORD_LEN);
if (rc < 0)
return rc;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x3390, reg_val, WORD_LEN);
if (rc < 0)
return rc;
}
break;
case CAMERA_EFFECT_PASTEL:
case CAMERA_EFFECT_MOSAIC:
case CAMERA_EFFECT_RESIZE:
return -EINVAL;
default: {
reg_val = 0x6440;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x338C, reg_addr, WORD_LEN);
if (rc < 0)
return rc;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x3390, reg_val, WORD_LEN);
if (rc < 0)
return rc;
return -EINVAL;
}
}
/* Refresh Sequencer */
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x338C, 0xA103, WORD_LEN);
if (rc < 0)
return rc;
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x3390, 0x0005, WORD_LEN);
return rc;
}
static int mt9d112_sensor_init_probe(const struct msm_camera_sensor_info *data)
{
uint16_t model_id = 0;
int rc = 0;
CDBG("init entry \n");
rc = mt9d112_reset(data);
if (rc < 0) {
CDBG("reset failed!\n");
goto init_probe_fail;
}
mdelay(5);
/* Micron suggested Power up block Start:
* Put MCU into Reset - Stop MCU */
rc = mt9d112_i2c_write(mt9d112_client->addr,
REG_MT9D112_MCU_BOOT, 0x0501, WORD_LEN);
if (rc < 0)
goto init_probe_fail;
/* Pull MCU from Reset - Start MCU */
rc = mt9d112_i2c_write(mt9d112_client->addr,
REG_MT9D112_MCU_BOOT, 0x0500, WORD_LEN);
if (rc < 0)
goto init_probe_fail;
mdelay(5);
/* Micron Suggested - Power up block */
rc = mt9d112_i2c_write(mt9d112_client->addr,
REG_MT9D112_SENSOR_RESET, 0x0ACC, WORD_LEN);
if (rc < 0)
goto init_probe_fail;
rc = mt9d112_i2c_write(mt9d112_client->addr,
REG_MT9D112_STANDBY_CONTROL, 0x0008, WORD_LEN);
if (rc < 0)
goto init_probe_fail;
/* FUSED_DEFECT_CORRECTION */
rc = mt9d112_i2c_write(mt9d112_client->addr,
0x33F4, 0x031D, WORD_LEN);
if (rc < 0)
goto init_probe_fail;
mdelay(5);
/* Micron suggested Power up block End */
/* Read the Model ID of the sensor */
rc = mt9d112_i2c_read(mt9d112_client->addr,
REG_MT9D112_MODEL_ID, &model_id, WORD_LEN);
if (rc < 0)
goto init_probe_fail;
CDBG("mt9d112 model_id = 0x%x\n", model_id);
/* Check if it matches it with the value in Datasheet */
if (model_id != MT9D112_MODEL_ID) {
rc = -EINVAL;
goto init_probe_fail;
}
rc = mt9d112_reg_init();
if (rc < 0)
goto init_probe_fail;
return rc;
init_probe_fail:
return rc;
}
int mt9d112_sensor_init(const struct msm_camera_sensor_info *data)
{
int rc = 0;
mt9d112_ctrl = kzalloc(sizeof(struct mt9d112_ctrl), GFP_KERNEL);
if (!mt9d112_ctrl) {
CDBG("mt9d112_init failed!\n");
rc = -ENOMEM;
goto init_done;
}
if (data)
mt9d112_ctrl->sensordata = data;
/* Input MCLK = 24MHz */
msm_camio_clk_rate_set(24000000);
mdelay(5);
msm_camio_camif_pad_reg_reset();
rc = mt9d112_sensor_init_probe(data);
if (rc < 0) {
CDBG("mt9d112_sensor_init failed!\n");
goto init_fail;
}
init_done:
return rc;
init_fail:
kfree(mt9d112_ctrl);
return rc;
}
static int mt9d112_init_client(struct i2c_client *client)
{
/* Initialize the MSM_CAMI2C Chip */
init_waitqueue_head(&mt9d112_wait_queue);
return 0;
}
int mt9d112_sensor_config(void __user *argp)
{
struct sensor_cfg_data cfg_data;
long rc = 0;
if (copy_from_user(&cfg_data,
(void *)argp,
sizeof(struct sensor_cfg_data)))
return -EFAULT;
/* down(&mt9d112_sem); */
CDBG("mt9d112_ioctl, cfgtype = %d, mode = %d\n",
cfg_data.cfgtype, cfg_data.mode);
switch (cfg_data.cfgtype) {
case CFG_SET_MODE:
rc = mt9d112_set_sensor_mode(
cfg_data.mode);
break;
case CFG_SET_EFFECT:
rc = mt9d112_set_effect(cfg_data.mode,
cfg_data.cfg.effect);
break;
case CFG_GET_AF_MAX_STEPS:
default:
rc = -EINVAL;
break;
}
/* up(&mt9d112_sem); */
return rc;
}
int mt9d112_sensor_release(void)
{
int rc = 0;
/* down(&mt9d112_sem); */
kfree(mt9d112_ctrl);
/* up(&mt9d112_sem); */
return rc;
}
static int mt9d112_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
int rc = 0;
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
rc = -ENOTSUPP;
goto probe_failure;
}
mt9d112_sensorw =
kzalloc(sizeof(struct mt9d112_work), GFP_KERNEL);
if (!mt9d112_sensorw) {
rc = -ENOMEM;
goto probe_failure;
}
i2c_set_clientdata(client, mt9d112_sensorw);
mt9d112_init_client(client);
mt9d112_client = client;
CDBG("mt9d112_probe succeeded!\n");
return 0;
probe_failure:
kfree(mt9d112_sensorw);
mt9d112_sensorw = NULL;
CDBG("mt9d112_probe failed!\n");
return rc;
}
static const struct i2c_device_id mt9d112_i2c_id[] = {
{ "mt9d112", 0},
{ },
};
static struct i2c_driver mt9d112_i2c_driver = {
.id_table = mt9d112_i2c_id,
.probe = mt9d112_i2c_probe,
.remove = __exit_p(mt9d112_i2c_remove),
.driver = {
.name = "mt9d112",
},
};
static int mt9d112_sensor_probe(const struct msm_camera_sensor_info *info,
struct msm_sensor_ctrl *s)
{
int rc = i2c_add_driver(&mt9d112_i2c_driver);
if (rc < 0 || mt9d112_client == NULL) {
rc = -ENOTSUPP;
goto probe_done;
}
/* Input MCLK = 24MHz */
msm_camio_clk_rate_set(24000000);
mdelay(5);
rc = mt9d112_sensor_init_probe(info);
if (rc < 0)
goto probe_done;
s->s_init = mt9d112_sensor_init;
s->s_release = mt9d112_sensor_release;
s->s_config = mt9d112_sensor_config;
probe_done:
CDBG("%s %s:%d\n", __FILE__, __func__, __LINE__);
return rc;
}
static int __mt9d112_probe(struct platform_device *pdev)
{
return msm_camera_drv_start(pdev, mt9d112_sensor_probe);
}
static struct platform_driver msm_camera_driver = {
.probe = __mt9d112_probe,
.driver = {
.name = "msm_camera_mt9d112",
.owner = THIS_MODULE,
},
};
static int __init mt9d112_init(void)
{
return platform_driver_register(&msm_camera_driver);
}
module_init(mt9d112_init);