/* * ssl3250a.c - ssl3250a flash/torch kernel driver * * Copyright (C) 2011-2013 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 #include #include #include #include #include #include #include #include #include #include #include #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; char devname[16]; }; 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, ®); 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(¶ms, (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, ®); 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, ®); 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, ®); 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(¶ms, (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, ¶ms, val); case NVC_SYNC_SLAVE: return ssl3250a_param_wr_s(info->s_info, ¶ms, val); case NVC_SYNC_STEREO: err = ssl3250a_param_wr_s(info, ¶ms, val); if (!(info->pdata->cfg & NVC_CFG_SYNC_I2C_MUX)) err |= ssl3250a_param_wr_s(info->s_info, ¶ms, 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; 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) strncpy(info->devname, info->pdata->dev_name, sizeof(info->devname) - 1); else strncpy(info->devname, "ssl3250a", sizeof(info->devname) - 1); if (info->pdata->num) snprintf(info->devname, sizeof(info->devname), "%s.%u", info->devname, info->pdata->num); info->miscdev.name = info->devname; 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__, info->devname); 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");