blob: 1ca27c26ef754fc8d040cf3d91341ba99885518c [file] [log] [blame]
/*
* Copyright (c) 2013 Intel Corporation. All Rights Reserved.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*/
#include <linux/bitops.h>
#include <linux/device.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <media/v4l2-device.h>
#include <asm/intel-mid.h>
#include "common.h"
/* Defines for OTP Data Registers */
#define IMX_OTP_START_ADDR 0x3B04
#define IMX_OTP_PAGE_SIZE 64
#define IMX_OTP_READY_REG 0x3B01
#define IMX_OTP_PAGE_REG 0x3B02
#define IMX_OTP_MODE_REG 0x3B00
#define IMX_OTP_PAGE_MAX 20
#define IMX_OTP_READY_REG_DONE 1
#define IMX_OTP_READ_ONETIME 32
#define IMX_OTP_MODE_READ 1
#define IMX227_OTP_START_ADDR 0x0A04
#define IMX227_OTP_ENABLE_REG 0x0A00
#define IMX227_OTP_READY_REG 0x0A01
#define IMX227_OTP_PAGE_REG 0x0A02
#define IMX227_OTP_READY_REG_DONE 1
#define IMX227_OTP_MODE_READ 1
static int
imx_read_otp_data(struct i2c_client *client, u16 len, u16 reg, void *val)
{
struct i2c_msg msg[2];
u16 data[IMX_SHORT_MAX] = { 0 };
int err;
if (len > IMX_BYTE_MAX) {
dev_err(&client->dev, "%s error, invalid data length\n",
__func__);
return -EINVAL;
}
memset(msg, 0 , sizeof(msg));
memset(data, 0 , sizeof(data));
msg[0].addr = client->addr;
msg[0].flags = 0;
msg[0].len = I2C_MSG_LENGTH;
msg[0].buf = (u8 *)data;
/* high byte goes first */
data[0] = cpu_to_be16(reg);
msg[1].addr = client->addr;
msg[1].len = len;
msg[1].flags = I2C_M_RD;
msg[1].buf = (u8 *)data;
err = i2c_transfer(client->adapter, msg, 2);
if (err != 2) {
if (err >= 0)
err = -EIO;
goto error;
}
memcpy(val, data, len);
return 0;
error:
dev_err(&client->dev, "read from offset 0x%x error %d", reg, err);
return err;
}
static int imx_read_otp_reg_array(struct i2c_client *client, u16 size, u16 addr,
u8 *buf)
{
u16 index;
int ret;
for (index = 0; index + IMX_OTP_READ_ONETIME <= size;
index += IMX_OTP_READ_ONETIME) {
ret = imx_read_otp_data(client, IMX_OTP_READ_ONETIME,
addr + index, &buf[index]);
if (ret)
return ret;
}
return 0;
}
void *imx_otp_read(struct v4l2_subdev *sd, u8 dev_addr,
u32 start_addr, u32 size)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 *buf;
int ret;
int i;
buf = devm_kzalloc(&client->dev, size, GFP_KERNEL);
if (!buf)
return ERR_PTR(-ENOMEM);
for (i = 0; i < IMX_OTP_PAGE_MAX; i++) {
/*set page NO.*/
ret = imx_write_reg(client, IMX_8BIT,
IMX_OTP_PAGE_REG, i & 0xff);
if (ret)
goto fail;
/*set read mode*/
ret = imx_write_reg(client, IMX_8BIT,
IMX_OTP_MODE_REG, IMX_OTP_MODE_READ);
if (ret)
goto fail;
/* Reading the OTP data array */
ret = imx_read_otp_reg_array(client, IMX_OTP_PAGE_SIZE,
IMX_OTP_START_ADDR, buf + i * IMX_OTP_PAGE_SIZE);
if (ret)
goto fail;
}
return buf;
fail:
/* Driver has failed to find valid data */
dev_err(&client->dev, "sensor found no valid OTP data\n");
return ERR_PTR(ret);
}
void *imx227_otp_read(struct v4l2_subdev *sd, u8 dev_addr,
u32 start_addr, u32 size)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 *buf;
int ret;
int i;
buf = devm_kzalloc(&client->dev, size, GFP_KERNEL);
if (!buf)
return ERR_PTR(-ENOMEM);
for (i = 0; i < IMX_OTP_PAGE_MAX; i++) {
/*set page NO.*/
ret = imx_write_reg(client, IMX_8BIT,
IMX227_OTP_PAGE_REG, i & 0xff);
if (ret)
goto fail;
/*set read mode*/
ret = imx_write_reg(client, IMX_8BIT,
IMX227_OTP_ENABLE_REG, IMX227_OTP_MODE_READ);
if (ret)
goto fail;
/* Reading the OTP data array */
ret = imx_read_otp_reg_array(client, IMX_OTP_PAGE_SIZE,
IMX227_OTP_START_ADDR, buf + i * IMX_OTP_PAGE_SIZE);
if (ret)
goto fail;
}
return buf;
fail:
/* Driver has failed to find valid data */
dev_err(&client->dev, "sensor found no valid OTP data\n");
return ERR_PTR(ret);
}