diff options
-rw-r--r-- | drivers/media/platform/tegra/ov5693.c | 110 | ||||
-rw-r--r-- | include/media/ov5693.h | 14 |
2 files changed, 122 insertions, 2 deletions
diff --git a/drivers/media/platform/tegra/ov5693.c b/drivers/media/platform/tegra/ov5693.c index c1ec02bdca3e..a03dcc7e74dd 100644 --- a/drivers/media/platform/tegra/ov5693.c +++ b/drivers/media/platform/tegra/ov5693.c @@ -77,6 +77,8 @@ struct ov5693_info { unsigned int edp_state; struct sysedp_consumer *sysedpc; char devname[16]; + struct ov5693_eeprom_data eeprom[OV5693_EEPROM_NUM_BLOCKS]; + u8 eeprom_buf[OV5693_EEPROM_SIZE]; }; struct ov5693_reg { @@ -3050,6 +3052,66 @@ static int ov5693_read_otp_bank(struct ov5693_info *info, return err; } +static int +ov5693_eeprom_device_release(struct ov5693_info *info) +{ + int i; + + for (i = 0; i < OV5693_EEPROM_NUM_BLOCKS; i++) { + if (info->eeprom[i].i2c_client != NULL) { + i2c_unregister_device(info->eeprom[i].i2c_client); + info->eeprom[i].i2c_client = NULL; + } + } + + return 0; +} + +static int +ov5693_eeprom_device_init(struct ov5693_info *info) +{ + char *dev_name = "eeprom_ov5693"; + static struct regmap_config eeprom_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + }; + int i; + int err; + + for (i = 0; i < OV5693_EEPROM_NUM_BLOCKS; i++) { + info->eeprom[i].adap = i2c_get_adapter( + info->i2c_client->adapter->nr); + memset(&info->eeprom[i].brd, 0, sizeof(info->eeprom[i].brd)); + strncpy(info->eeprom[i].brd.type, dev_name, + sizeof(info->eeprom[i].brd.type)); + info->eeprom[i].brd.addr = OV5693_EEPROM_ADDRESS + i; + info->eeprom[i].i2c_client = i2c_new_device( + info->eeprom[i].adap, &info->eeprom[i].brd); + + info->eeprom[i].regmap = devm_regmap_init_i2c( + info->eeprom[i].i2c_client, &eeprom_regmap_config); + if (IS_ERR(info->eeprom[i].regmap)) { + err = PTR_ERR(info->eeprom[i].regmap); + ov5693_eeprom_device_release(info); + return err; + } + } + + return 0; +} + +static int +ov5693_read_eeprom(struct ov5693_info *info, u8 reg, u16 length, u8 *buf) +{ + return regmap_raw_read(info->eeprom[0].regmap, reg, &buf[reg], length); +} + +static int +ov5693_write_eeprom(struct ov5693_info *info, u16 addr, u8 val) +{ + return regmap_write(info->eeprom[addr >> 8].regmap, addr & 0xFF, val); +} + static long ov5693_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { struct ov5693_info *info = file->private_data; @@ -3170,6 +3232,42 @@ static long ov5693_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return 0; } + case OV5693_IOCTL_GET_EEPROM_DATA: + { + ov5693_read_eeprom(info, + 0, + OV5693_EEPROM_SIZE, + info->eeprom_buf); + + if (copy_to_user((void __user *)arg, + info->eeprom_buf, OV5693_EEPROM_SIZE)) { + dev_err(&info->i2c_client->dev, + "%s:Failed to copy status to user\n", + __func__); + return -EFAULT; + } + } + return 0; + + case OV5693_IOCTL_SET_EEPROM_DATA: + { + int i; + if (copy_from_user(info->eeprom_buf, + (const void __user *)arg, OV5693_EEPROM_SIZE)) { + dev_err(&info->i2c_client->dev, + "%s:Failed to read from user buffer\n", + __func__); + return -EFAULT; + } + for (i = 0; i < OV5693_EEPROM_SIZE; i++) { + ov5693_write_eeprom(info, + i, + info->eeprom_buf[i]); + msleep(20); + } + } + return 0; + default: dev_err(&info->i2c_client->dev, "%s unsupported ioctl: %x\n", __func__, cmd); @@ -3239,6 +3337,7 @@ static int ov5693_remove(struct i2c_client *client) dev_dbg(&info->i2c_client->dev, "%s\n", __func__); misc_deregister(&info->miscdev); sysedp_free_consumer(info->sysedpc); + ov5693_eeprom_device_release(info); ov5693_del(info); return 0; } @@ -3380,7 +3479,7 @@ static int ov5693_probe( unsigned long clock_probe_rate; int err; const char *mclk_name; - static struct regmap_config ad5823_regmap_config = { + static struct regmap_config ov5693_regmap_config = { .reg_bits = 16, .val_bits = 8, }; @@ -3422,7 +3521,7 @@ static int ov5693_probe( } } - info->regmap = devm_regmap_init_i2c(client, &ad5823_regmap_config); + info->regmap = devm_regmap_init_i2c(client, &ov5693_regmap_config); if (IS_ERR(info->regmap)) { err = PTR_ERR(info->regmap); dev_err(&client->dev, @@ -3430,6 +3529,13 @@ static int ov5693_probe( return err; } + err = ov5693_eeprom_device_init(info); + if (err) { + dev_err(&client->dev, + "Failed to allocate eeprom register map: %d\n", err); + return err; + } + mclk_name = info->pdata->mclk_name ? info->pdata->mclk_name : "default_mclk"; info->mclk = devm_clk_get(&client->dev, mclk_name); diff --git a/include/media/ov5693.h b/include/media/ov5693.h index 27fc25a49bad..1804efab1539 100644 --- a/include/media/ov5693.h +++ b/include/media/ov5693.h @@ -40,9 +40,16 @@ struct ov5693_otp_bank) #define OV5693_IOCTL_SET_CAL_DATA _IOW('o', 15, \ struct ov5693_cal_data) +#define OV5693_IOCTL_GET_EEPROM_DATA _IOR('o', 20, __u8 *) +#define OV5693_IOCTL_SET_EEPROM_DATA _IOW('o', 21, __u8 *) #define OV5693_INVALID_COARSE_TIME -1 +#define OV5693_EEPROM_ADDRESS 0x50 +#define OV5693_EEPROM_SIZE 1024 +#define OV5693_EEPROM_BLOCK_SIZE (1 << 8) +#define OV5693_EEPROM_NUM_BLOCKS \ + (OV5693_EEPROM_SIZE / OV5693_EEPROM_BLOCK_SIZE) struct ov5693_mode { int res_x; @@ -94,6 +101,13 @@ enum ov5693_gpio_type { OV5693_GPIO_TYPE_PWRDN = 0, }; +struct ov5693_eeprom_data { + struct i2c_client *i2c_client; + struct i2c_adapter *adap; + struct i2c_board_info brd; + struct regmap *regmap; +}; + struct ov5693_power_rail { struct regulator *dvdd; struct regulator *avdd; |