blob: 2656138099e60fcacd4ebb348a628cbba84e9d97 [file] [log] [blame]
/*
* ssl3250a.c - ssl3250a flash/torch kernel driver
*
* Copyright (C) 2011 NVIDIA Corporation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
* 02111-1307, USA
*/
/* Implementation
* --------------
* The board level details about the device need to be provided in the board
* file with the ssl3250a_platform_data structure.
* Standard among NVC kernel drivers in this structure is:
* .cfg = Use the NVC_CFG_ defines that are in nvc_torch.h.
* Descriptions of the configuration options are with the defines.
* This value is typically 0.
* .num = The number of the instance of the device. This should start at 1 and
* and increment for each device on the board. This number will be
* appended to the MISC driver name, Example: /dev/ssl3250a.1
* .sync = If there is a need to synchronize two devices, then this value is
* the number of the device instance this device is allowed to sync to.
* This is typically used for stereo applications.
* .dev_name = The MISC driver name the device registers as. If not used,
* then the part number of the device is used for the driver name.
* If using the NVC user driver then use the name found in this
* driver under _default_pdata.
*
* The following is specific to NVC kernel flash/torch drivers:
* .pinstate = a pointer to the nvc_torch_pin_state structure. This
* structure gives the details of which VI GPIO to use to trigger
* the flash. The mask tells which pin and the values is the
* level. For example, if VI GPIO pin 6 is used, then
* .mask = 0x0040
* .values = 0x0040
* If VI GPIO pin 0 is used, then
* .mask = 0x0001
* .values = 0x0001
* This is typically just one pin but there is some legacy
* here that insinuates more than one pin can be used.
* When the flash level is set, then the driver will return the
* value in values. When the flash level is off, the driver will
* return 0 for the values to deassert the signal.
* If a VI GPIO is not used, then the mask and values must be set
* to 0. The flash may then be triggered via I2C instead.
* However, a VI GPIO is strongly encouraged since it allows
* tighter timing with the picture taken as well as reduced power
* by asserting the trigger signal for only when needed.
* .max_amp_torch = Is the maximum torch value allowed. The value is 0 to
* _MAX_TORCH_LEVEL. This is to allow a limit to the amount
* of amps used. If left blank then _MAX_TORCH_LEVEL will be
* used.
* .max_amp_flash = Is the maximum flash value allowed. The value is 0 to
* _MAX_FLASH_LEVEL. This is to allow a limit to the amount
* of amps used. If left blank then _MAX_FLASH_LEVEL will be
* used.
*
* The following is specific to only this NVC kernel flash/torch driver:
* .gpio_act = Is the GPIO needed to control the ACT signal. If tied high,
* then this can be left blank.
*
* Power Requirements
* The board power file must contain the following labels for the power
* regulator(s) of this device:
* "vdd_i2c" = the power regulator for the I2C power.
* Note that this device is typically connected directly to the battery rail
* and does not need a source power regulator (vdd).
*
* The above values should be all that is needed to use the device with this
* driver. Modifications of this driver should not be needed.
*/
#include <linux/fs.h>
#include <linux/i2c.h>
#include <linux/miscdevice.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/uaccess.h>
#include <linux/list.h>
#include <linux/regulator/consumer.h>
#include <linux/gpio.h>
#include <linux/module.h>
#include <media/nvc.h>
#include <media/ssl3250a.h>
#define SSL3250A_REG_AMP 0x00
#define SSL3250A_REG_TMR 0x01
#define SSL3250A_REG_STRB 0x02
#define SSL3250A_REG_STS 0x03
#define ssl3250a_flash_cap_size (sizeof(ssl3250a_flash_cap.numberoflevels) \
+ (sizeof(ssl3250a_flash_cap.levels[0]) \
* (SSL3250A_MAX_FLASH_LEVEL + 1)))
#define ssl3250a_torch_cap_size (sizeof(ssl3250a_torch_cap.numberoflevels) \
+ (sizeof(ssl3250a_torch_cap.guidenum[0]) \
* (SSL3250A_MAX_TORCH_LEVEL + 1)))
static struct nvc_torch_flash_capabilities ssl3250a_flash_cap = {
SSL3250A_MAX_FLASH_LEVEL + 1,
{
{ 0, 0xFFFFFFFF, 0 },
{ 215, 820, 20 },
{ 230, 820, 20 },
{ 245, 820, 20 },
{ 260, 820, 20 },
{ 275, 820, 20 },
{ 290, 820, 20 },
{ 305, 820, 20 },
{ 320, 820, 20 },
{ 335, 820, 20 },
{ 350, 820, 20 },
{ 365, 820, 20 },
{ 380, 820, 20 },
{ 395, 820, 20 },
{ 410, 820, 20 },
{ 425, 820, 20 },
{ 440, 820, 20 },
{ 455, 820, 20 },
{ 470, 820, 20 },
{ 485, 820, 20 },
{ 500, 820, 20 }
}
};
static struct nvc_torch_torch_capabilities ssl3250a_torch_cap = {
SSL3250A_MAX_TORCH_LEVEL + 1,
{
0,
50,
65,
80,
95,
110,
125,
140,
155,
170,
185,
200
}
};
struct ssl3250a_info {
atomic_t in_use;
struct i2c_client *i2c_client;
struct ssl3250a_platform_data *pdata;
struct miscdevice miscdev;
struct list_head list;
int pwr_api;
int pwr_dev;
struct nvc_regulator vreg_i2c;
u8 s_mode;
struct ssl3250a_info *s_info;
};
static struct nvc_torch_pin_state ssl3250a_default_pinstate = {
.mask = 0x0000,
.values = 0x0000,
};
static struct ssl3250a_platform_data ssl3250a_default_pdata = {
.cfg = 0,
.num = 0,
.sync = 0,
.dev_name = "torch",
.pinstate = &ssl3250a_default_pinstate,
.max_amp_torch = SSL3250A_MAX_TORCH_LEVEL,
.max_amp_flash = SSL3250A_MAX_FLASH_LEVEL,
};
static LIST_HEAD(ssl3250a_info_list);
static DEFINE_SPINLOCK(ssl3250a_spinlock);
static int ssl3250a_i2c_rd(struct ssl3250a_info *info, u8 reg, u8 *val)
{
struct i2c_msg msg[2];
u8 buf[2];
buf[0] = reg;
msg[0].addr = info->i2c_client->addr;
msg[0].flags = 0;
msg[0].len = 1;
msg[0].buf = &buf[0];
msg[1].addr = info->i2c_client->addr;
msg[1].flags = I2C_M_RD;
msg[1].len = 1;
msg[1].buf = &buf[1];
*val = 0;
if (i2c_transfer(info->i2c_client->adapter, msg, 2) != 2)
return -EIO;
*val = buf[1];
return 0;
}
static int ssl3250a_i2c_wr(struct ssl3250a_info *info, u8 reg, u8 val)
{
struct i2c_msg msg;
u8 buf[2];
buf[0] = reg;
buf[1] = val;
msg.addr = info->i2c_client->addr;
msg.flags = 0;
msg.len = 2;
msg.buf = &buf[0];
if (i2c_transfer(info->i2c_client->adapter, &msg, 1) != 1)
return -EIO;
return 0;
}
static void ssl3250a_gpio_act(struct ssl3250a_info *info, int val)
{
int prev_val;
if (info->pdata->gpio_act) {
prev_val = gpio_get_value(info->pdata->gpio_act);
if (val != prev_val) {
gpio_set_value(info->pdata->gpio_act, val);
if (val)
mdelay(1); /* delay for device startup */
}
}
}
static void ssl3250a_pm_regulator_put(struct nvc_regulator *sreg)
{
regulator_put(sreg->vreg);
sreg->vreg = NULL;
}
static int ssl3250a_pm_regulator_get(struct ssl3250a_info *info,
struct nvc_regulator *sreg,
char vreg_name[])
{
int err = 0;
sreg->vreg_flag = 0;
sreg->vreg = regulator_get(&info->i2c_client->dev, vreg_name);
if (WARN_ON(IS_ERR(sreg->vreg))) {
dev_err(&info->i2c_client->dev,
"%s err for regulator: %s err: %d\n",
__func__, vreg_name, (int)sreg->vreg);
err = PTR_ERR(sreg->vreg);
sreg->vreg = NULL;
} else {
sreg->vreg_name = vreg_name;
dev_dbg(&info->i2c_client->dev,
"%s vreg_name: %s\n",
__func__, sreg->vreg_name);
}
return err;
}
static int ssl3250a_pm_regulator_en(struct ssl3250a_info *info,
struct nvc_regulator *sreg)
{
int err = 0;
if (!sreg->vreg_flag && (sreg->vreg != NULL)) {
err = regulator_enable(sreg->vreg);
if (!err) {
dev_dbg(&info->i2c_client->dev,
"%s vreg_name: %s\n",
__func__, sreg->vreg_name);
sreg->vreg_flag = 1;
err = 1; /* flag regulator state change */
} else {
dev_err(&info->i2c_client->dev,
"%s err, regulator: %s\n",
__func__, sreg->vreg_name);
}
}
return err;
}
static int ssl3250a_pm_regulator_dis(struct ssl3250a_info *info,
struct nvc_regulator *sreg)
{
int err = 0;
if (sreg->vreg_flag && (sreg->vreg != NULL)) {
err = regulator_disable(sreg->vreg);
if (!err)
dev_dbg(&info->i2c_client->dev,
"%s vreg_name: %s\n",
__func__, sreg->vreg_name);
else
dev_err(&info->i2c_client->dev,
"%s err, regulator: %s\n",
__func__, sreg->vreg_name);
}
sreg->vreg_flag = 0;
return err;
}
static int ssl3250a_pm_wr(struct ssl3250a_info *info, int pwr)
{
int err = 0;
if (pwr == info->pwr_dev)
return 0;
switch (pwr) {
case NVC_PWR_OFF:
if ((info->pdata->cfg & NVC_CFG_OFF2STDBY) ||
(info->pdata->cfg & NVC_CFG_BOOT_INIT)) {
pwr = NVC_PWR_STDBY;
} else {
ssl3250a_gpio_act(info, 0);
err = ssl3250a_pm_regulator_dis(info, &info->vreg_i2c);
break;
}
case NVC_PWR_STDBY_OFF:
if ((info->pdata->cfg & NVC_CFG_OFF2STDBY) ||
(info->pdata->cfg & NVC_CFG_BOOT_INIT)) {
pwr = NVC_PWR_STDBY;
} else {
ssl3250a_gpio_act(info, 0);
err = ssl3250a_pm_regulator_en(info, &info->vreg_i2c);
break;
}
case NVC_PWR_STDBY:
err = ssl3250a_pm_regulator_en(info, &info->vreg_i2c);
ssl3250a_gpio_act(info, 1);
err |= ssl3250a_i2c_wr(info, SSL3250A_REG_AMP, 0x00);
break;
case NVC_PWR_COMM:
case NVC_PWR_ON:
err = ssl3250a_pm_regulator_en(info, &info->vreg_i2c);
ssl3250a_gpio_act(info, 1);
break;
default:
err = -EINVAL;
break;
}
if (err < 0) {
dev_err(&info->i2c_client->dev, "%s error\n", __func__);
pwr = NVC_PWR_ERR;
}
info->pwr_dev = pwr;
if (err > 0)
return 0;
return err;
}
static int ssl3250a_pm_wr_s(struct ssl3250a_info *info, int pwr)
{
int err1 = 0;
int err2 = 0;
if ((info->s_mode == NVC_SYNC_OFF) ||
(info->s_mode == NVC_SYNC_MASTER) ||
(info->s_mode == NVC_SYNC_STEREO))
err1 = ssl3250a_pm_wr(info, pwr);
if ((info->s_mode == NVC_SYNC_SLAVE) ||
(info->s_mode == NVC_SYNC_STEREO))
err2 = ssl3250a_pm_wr(info->s_info, pwr);
return err1 | err2;
}
static int ssl3250a_pm_api_wr(struct ssl3250a_info *info, int pwr)
{
int err = 0;
if (!pwr || (pwr > NVC_PWR_ON))
return 0;
if (pwr > info->pwr_dev)
err = ssl3250a_pm_wr_s(info, pwr);
if (!err)
info->pwr_api = pwr;
else
info->pwr_api = NVC_PWR_ERR;
if (info->pdata->cfg & NVC_CFG_NOERR)
return 0;
return err;
}
static int ssl3250a_pm_dev_wr(struct ssl3250a_info *info, int pwr)
{
if (pwr < info->pwr_api)
pwr = info->pwr_api;
return ssl3250a_pm_wr(info, pwr);
}
static void ssl3250a_pm_exit(struct ssl3250a_info *info)
{
ssl3250a_pm_wr_s(info, NVC_PWR_OFF);
ssl3250a_pm_regulator_put(&info->vreg_i2c);
}
static void ssl3250a_pm_init(struct ssl3250a_info *info)
{
ssl3250a_pm_regulator_get(info, &info->vreg_i2c, "vdd_i2c");
}
static int ssl3250a_dev_id(struct ssl3250a_info *info)
{
u8 addr;
u8 reg;
int err;
ssl3250a_pm_dev_wr(info, NVC_PWR_COMM);
/* There isn't a device ID so we just check that all the registers
* equal their startup defaults, which in this case, is 0.
*/
for (addr = 0; addr < SSL3250A_REG_STS; addr++) {
err = ssl3250a_i2c_rd(info, addr, &reg);
if (err) {
break;
} else {
if (reg) {
err = -ENODEV;
break;
}
}
}
ssl3250a_pm_dev_wr(info, NVC_PWR_OFF);
return err;
}
static int ssl3250a_param_rd(struct ssl3250a_info *info, long arg)
{
struct nvc_param params;
struct nvc_torch_pin_state pinstate;
const void *data_ptr;
u32 data_size = 0;
int err;
u8 reg;
if (copy_from_user(&params,
(const void __user *)arg,
sizeof(struct nvc_param))) {
dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
__func__, __LINE__);
return -EINVAL;
}
if (info->s_mode == NVC_SYNC_SLAVE)
info = info->s_info;
switch (params.param) {
case NVC_PARAM_FLASH_CAPS:
dev_dbg(&info->i2c_client->dev, "%s FLASH_CAPS\n", __func__);
data_ptr = &ssl3250a_flash_cap;
data_size = ssl3250a_flash_cap_size;
break;
case NVC_PARAM_FLASH_LEVEL:
ssl3250a_pm_dev_wr(info, NVC_PWR_COMM);
err = ssl3250a_i2c_rd(info, SSL3250A_REG_AMP, &reg);
ssl3250a_pm_dev_wr(info, NVC_PWR_OFF);
if (err < 0)
return err;
reg >>= 3; /*7:3=flash amps*/
reg &= 0x1F; /*4:0=flash amps*/
if (reg < 12) /*flash starts at 12*/
reg = 0; /*<12=torch or off*/
else
reg -= 11; /*create flash index*/
dev_dbg(&info->i2c_client->dev, "%s FLASH_LEVEL: %u\n",
__func__,
(unsigned)ssl3250a_flash_cap.levels[reg].guidenum);
data_ptr = &ssl3250a_flash_cap.levels[reg].guidenum;
data_size = sizeof(ssl3250a_flash_cap.levels[reg].guidenum);
break;
case NVC_PARAM_TORCH_CAPS:
dev_dbg(&info->i2c_client->dev, "%s TORCH_CAPS\n", __func__);
data_ptr = &ssl3250a_torch_cap;
data_size = ssl3250a_torch_cap_size;
break;
case NVC_PARAM_TORCH_LEVEL:
ssl3250a_pm_dev_wr(info, NVC_PWR_COMM);
err = ssl3250a_i2c_rd(info, SSL3250A_REG_AMP, &reg);
ssl3250a_pm_dev_wr(info, NVC_PWR_OFF);
if (err < 0)
return err;
reg >>= 3; /*7:3=torch amps*/
reg &= 0x1F; /*4:0=torch amps*/
if (reg > 11) /*flash starts at 12*/
reg = 0; /*>11=flash mode (torch off)*/
dev_dbg(&info->i2c_client->dev, "%s TORCH_LEVEL: %u\n",
__func__,
(unsigned)ssl3250a_torch_cap.guidenum[reg]);
data_ptr = &ssl3250a_torch_cap.guidenum[reg];
data_size = sizeof(ssl3250a_torch_cap.guidenum[reg]);
break;
case NVC_PARAM_FLASH_PIN_STATE:
pinstate.mask = info->pdata->pinstate->mask;
ssl3250a_pm_dev_wr(info, NVC_PWR_COMM);
err = ssl3250a_i2c_rd(info, SSL3250A_REG_AMP, &reg);
ssl3250a_pm_dev_wr(info, NVC_PWR_OFF);
if (err < 0)
return err;
reg >>= 3; /*7:3=flash amps*/
reg &= 0x1F; /*4:0=flash amps*/
if (reg < 12) /*flash starts at 12*/
pinstate.values = 0; /*deassert strobe*/
else
/*assert strobe*/
pinstate.values = info->pdata->pinstate->values;
dev_dbg(&info->i2c_client->dev, "%s FLASH_PIN_STATE: %x&%x\n",
__func__, pinstate.mask, pinstate.values);
data_ptr = &pinstate;
data_size = sizeof(struct nvc_torch_pin_state);
break;
case NVC_PARAM_STEREO:
dev_dbg(&info->i2c_client->dev, "%s STEREO: %d\n",
__func__, info->s_mode);
data_ptr = &info->s_mode;
data_size = sizeof(info->s_mode);
break;
default:
dev_err(&info->i2c_client->dev,
"%s unsupported parameter: %d\n",
__func__, params.param);
return -EINVAL;
}
if (params.sizeofvalue < data_size) {
dev_err(&info->i2c_client->dev,
"%s data size mismatch %d != %d\n",
__func__, params.sizeofvalue, data_size);
return -EINVAL;
}
if (copy_to_user((void __user *)params.p_value,
data_ptr,
data_size)) {
dev_err(&info->i2c_client->dev,
"%s copy_to_user err line %d\n",
__func__, __LINE__);
return -EFAULT;
}
return 0;
}
static int ssl3250a_param_wr_s(struct ssl3250a_info *info,
struct nvc_param *params,
u8 val)
{
int err;
switch (params->param) {
case NVC_PARAM_FLASH_LEVEL:
dev_dbg(&info->i2c_client->dev, "%s FLASH_LEVEL: %d\n",
__func__, val);
ssl3250a_pm_dev_wr(info, NVC_PWR_ON);
if (val > ssl3250a_default_pdata.max_amp_flash)
val = ssl3250a_default_pdata.max_amp_flash;
/*Amp limit values are in the board-sensors file.*/
if (info->pdata->max_amp_flash &&
(val > info->pdata->max_amp_flash))
val = info->pdata->max_amp_flash;
if (val) {
val += 11; /*flash starts at 12*/
val <<= 3; /*7:3=flash/torch amps*/
}
err = ssl3250a_i2c_wr(info, SSL3250A_REG_AMP, val);
if (!val) /*turn pwr off if no flash && no pwr_api*/
ssl3250a_pm_dev_wr(info, NVC_PWR_OFF);
return err;
case NVC_PARAM_TORCH_LEVEL:
dev_dbg(&info->i2c_client->dev, "%s TORCH_LEVEL: %d\n",
__func__, val);
ssl3250a_pm_dev_wr(info, NVC_PWR_ON);
if (val > ssl3250a_default_pdata.max_amp_torch)
val = ssl3250a_default_pdata.max_amp_torch;
/*Amp limit values are in the board-sensors file.*/
if (info->pdata->max_amp_torch &&
(val > info->pdata->max_amp_torch))
val = info->pdata->max_amp_torch;
if (val)
val <<= 3; /*7:3=flash/torch amps*/
err = ssl3250a_i2c_wr(info, SSL3250A_REG_AMP, val);
if (!val) /*turn pwr off if no torch && no pwr_api*/
ssl3250a_pm_dev_wr(info, NVC_PWR_OFF);
return err;
case NVC_PARAM_FLASH_PIN_STATE:
dev_dbg(&info->i2c_client->dev, "%s FLASH_PIN_STATE: %d\n",
__func__, val);
if (val)
val = 0x01; /*0:0=soft trigger*/
return ssl3250a_i2c_wr(info, SSL3250A_REG_STRB, val);
default:
dev_err(&info->i2c_client->dev,
"%s unsupported parameter: %d\n",
__func__, params->param);
return -EINVAL;
}
}
static int ssl3250a_param_wr(struct ssl3250a_info *info, long arg)
{
struct nvc_param params;
u8 val;
int err = 0;
if (copy_from_user(&params,
(const void __user *)arg,
sizeof(struct nvc_param))) {
dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
__func__, __LINE__);
return -EINVAL;
}
if (copy_from_user(&val, (const void __user *)params.p_value,
sizeof(val))) {
dev_err(&info->i2c_client->dev, "%s %d copy_from_user err\n",
__func__, __LINE__);
return -EINVAL;
}
/* parameters independent of sync mode */
switch (params.param) {
case NVC_PARAM_STEREO:
dev_dbg(&info->i2c_client->dev, "%s STEREO: %d\n",
__func__, (int)val);
if (val == info->s_mode)
return 0;
switch (val) {
case NVC_SYNC_OFF:
info->s_mode = val;
if (info->s_info != NULL) {
info->s_info->s_mode = val;
ssl3250a_pm_wr(info->s_info, NVC_PWR_OFF);
}
break;
case NVC_SYNC_MASTER:
info->s_mode = val;
if (info->s_info != NULL)
info->s_info->s_mode = val;
break;
case NVC_SYNC_SLAVE:
case NVC_SYNC_STEREO:
if (info->s_info != NULL) {
/* sync power */
info->s_info->pwr_api = info->pwr_api;
err = ssl3250a_pm_wr(info->s_info,
info->pwr_dev);
if (!err) {
info->s_mode = val;
info->s_info->s_mode = val;
} else {
ssl3250a_pm_wr(info->s_info,
NVC_PWR_OFF);
err = -EIO;
}
} else {
err = -EINVAL;
}
break;
default:
err = -EINVAL;
}
if (info->pdata->cfg & NVC_CFG_NOERR)
return 0;
return err;
default:
/* parameters dependent on sync mode */
switch (info->s_mode) {
case NVC_SYNC_OFF:
case NVC_SYNC_MASTER:
return ssl3250a_param_wr_s(info, &params, val);
case NVC_SYNC_SLAVE:
return ssl3250a_param_wr_s(info->s_info,
&params,
val);
case NVC_SYNC_STEREO:
err = ssl3250a_param_wr_s(info, &params, val);
if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX))
err |= ssl3250a_param_wr_s(info->s_info,
&params,
val);
return err;
default:
dev_err(&info->i2c_client->dev, "%s %d internal err\n",
__func__, __LINE__);
return -EINVAL;
}
}
}
static long ssl3250a_ioctl(struct file *file,
unsigned int cmd,
unsigned long arg)
{
struct ssl3250a_info *info = file->private_data;
int pwr;
switch (cmd) {
case NVC_IOCTL_PARAM_WR:
return ssl3250a_param_wr(info, arg);
case NVC_IOCTL_PARAM_RD:
return ssl3250a_param_rd(info, arg);
case NVC_IOCTL_PWR_WR:
/* This is a Guaranteed Level of Service (GLOS) call */
pwr = (int)arg * 2;
dev_dbg(&info->i2c_client->dev, "%s PWR_WR: %d\n",
__func__, pwr);
return ssl3250a_pm_api_wr(info, pwr);
case NVC_IOCTL_PWR_RD:
if (info->s_mode == NVC_SYNC_SLAVE)
pwr = info->s_info->pwr_api / 2;
else
pwr = info->pwr_api / 2;
dev_dbg(&info->i2c_client->dev, "%s PWR_RD: %d\n",
__func__, pwr);
if (copy_to_user((void __user *)arg, (const void *)&pwr,
sizeof(pwr))) {
dev_err(&info->i2c_client->dev,
"%s copy_to_user err line %d\n",
__func__, __LINE__);
return -EFAULT;
}
return 0;
default:
dev_err(&info->i2c_client->dev, "%s unsupported ioctl: %x\n",
__func__, cmd);
return -EINVAL;
}
}
static int ssl3250a_sync_en(int dev1, int dev2)
{
struct ssl3250a_info *sync1 = NULL;
struct ssl3250a_info *sync2 = NULL;
struct ssl3250a_info *pos = NULL;
rcu_read_lock();
list_for_each_entry_rcu(pos, &ssl3250a_info_list, list) {
if (pos->pdata->num == dev1) {
sync1 = pos;
break;
}
}
pos = NULL;
list_for_each_entry_rcu(pos, &ssl3250a_info_list, list) {
if (pos->pdata->num == dev2) {
sync2 = pos;
break;
}
}
rcu_read_unlock();
if (sync1 != NULL)
sync1->s_info = NULL;
if (sync2 != NULL)
sync2->s_info = NULL;
if (!dev1 && !dev2)
return 0; /* no err if default instance 0's used */
if (dev1 == dev2)
return -EINVAL; /* err if sync instance is itself */
if ((sync1 != NULL) && (sync2 != NULL)) {
sync1->s_info = sync2;
sync2->s_info = sync1;
}
return 0;
}
static int ssl3250a_sync_dis(struct ssl3250a_info *info)
{
if (info->s_info != NULL) {
info->s_info->s_mode = 0;
info->s_info->s_info = NULL;
info->s_mode = 0;
info->s_info = NULL;
return 0;
}
return -EINVAL;
}
static int ssl3250a_open(struct inode *inode, struct file *file)
{
struct ssl3250a_info *info = NULL;
struct ssl3250a_info *pos = NULL;
int err;
rcu_read_lock();
list_for_each_entry_rcu(pos, &ssl3250a_info_list, list) {
if (pos->miscdev.minor == iminor(inode)) {
info = pos;
break;
}
}
rcu_read_unlock();
if (!info)
return -ENODEV;
err = ssl3250a_sync_en(info->pdata->num, info->pdata->sync);
if (err == -EINVAL)
dev_err(&info->i2c_client->dev,
"%s err: invalid num (%u) and sync (%u) instance\n",
__func__, info->pdata->num, info->pdata->sync);
if (atomic_xchg(&info->in_use, 1))
return -EBUSY;
if (info->s_info != NULL) {
if (atomic_xchg(&info->s_info->in_use, 1))
return -EBUSY;
}
file->private_data = info;
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
return 0;
}
static int ssl3250a_release(struct inode *inode, struct file *file)
{
struct ssl3250a_info *info = file->private_data;
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
ssl3250a_pm_wr_s(info, NVC_PWR_OFF);
file->private_data = NULL;
WARN_ON(!atomic_xchg(&info->in_use, 0));
if (info->s_info != NULL)
WARN_ON(!atomic_xchg(&info->s_info->in_use, 0));
ssl3250a_sync_dis(info);
return 0;
}
static const struct file_operations ssl3250a_fileops = {
.owner = THIS_MODULE,
.open = ssl3250a_open,
.unlocked_ioctl = ssl3250a_ioctl,
.release = ssl3250a_release,
};
static void ssl3250a_del(struct ssl3250a_info *info)
{
ssl3250a_pm_exit(info);
ssl3250a_sync_dis(info);
spin_lock(&ssl3250a_spinlock);
list_del_rcu(&info->list);
spin_unlock(&ssl3250a_spinlock);
synchronize_rcu();
}
static int ssl3250a_remove(struct i2c_client *client)
{
struct ssl3250a_info *info = i2c_get_clientdata(client);
dev_dbg(&info->i2c_client->dev, "%s\n", __func__);
misc_deregister(&info->miscdev);
ssl3250a_del(info);
return 0;
}
static int ssl3250a_probe(
struct i2c_client *client,
const struct i2c_device_id *id)
{
struct ssl3250a_info *info;
char dname[16];
int err;
dev_dbg(&client->dev, "%s\n", __func__);
info = devm_kzalloc(&client->dev, sizeof(*info), GFP_KERNEL);
if (info == NULL) {
dev_err(&client->dev, "%s: kzalloc error\n", __func__);
return -ENOMEM;
}
info->i2c_client = client;
if (client->dev.platform_data) {
info->pdata = client->dev.platform_data;
} else {
info->pdata = &ssl3250a_default_pdata;
dev_dbg(&client->dev,
"%s No platform data. Using defaults.\n",
__func__);
}
i2c_set_clientdata(client, info);
INIT_LIST_HEAD(&info->list);
spin_lock(&ssl3250a_spinlock);
list_add_rcu(&info->list, &ssl3250a_info_list);
spin_unlock(&ssl3250a_spinlock);
ssl3250a_pm_init(info);
err = ssl3250a_dev_id(info);
if (err < 0) {
dev_err(&client->dev, "%s device not found\n", __func__);
if (info->pdata->cfg & NVC_CFG_NODEV) {
ssl3250a_del(info);
return -ENODEV;
}
} else {
dev_dbg(&client->dev, "%s device found\n", __func__);
}
if (info->pdata->dev_name != 0)
strcpy(dname, info->pdata->dev_name);
else
strcpy(dname, "ssl3250a");
if (info->pdata->num)
snprintf(dname, sizeof(dname), "%s.%u",
dname, info->pdata->num);
info->miscdev.name = dname;
info->miscdev.fops = &ssl3250a_fileops;
info->miscdev.minor = MISC_DYNAMIC_MINOR;
if (misc_register(&info->miscdev)) {
dev_err(&client->dev, "%s unable to register misc device %s\n",
__func__, dname);
ssl3250a_del(info);
return -ENODEV;
}
return 0;
}
static const struct i2c_device_id ssl3250a_id[] = {
{ "ssl3250a", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, ssl3250a_id);
static struct i2c_driver ssl3250a_i2c_driver = {
.driver = {
.name = "ssl3250a",
.owner = THIS_MODULE,
},
.id_table = ssl3250a_id,
.probe = ssl3250a_probe,
.remove = ssl3250a_remove,
};
static int __init ssl3250a_init(void)
{
return i2c_add_driver(&ssl3250a_i2c_driver);
}
static void __exit ssl3250a_exit(void)
{
i2c_del_driver(&ssl3250a_i2c_driver);
}
module_init(ssl3250a_init);
module_exit(ssl3250a_exit);
MODULE_LICENSE("GPL");