Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9a22b945 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: camera: add qup i2c support for camera sensor devices"

parents 69fa876b a431ad6d
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -5,4 +5,4 @@ ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_sensor_io
ccflags-y += -Idrivers/media/platform/msm/camera/cam_sensor_module/cam_cci
ccflags-y += -Idrivers/media/platform/msm/camera/cam_req_mgr

obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io.o cam_sensor_cci_i2c.o
obj-$(CONFIG_SPECTRA_CAMERA) += cam_sensor_io.o cam_sensor_cci_i2c.o cam_sensor_qup_i2c.o
+61 −1
Original line number Diff line number Diff line
@@ -75,4 +75,64 @@ int32_t cam_cci_i2c_poll(struct cam_sensor_cci_client *client,
	enum camera_sensor_i2c_type addr_type,
	uint32_t delay_ms);

#endif /* _CAM_SENSOR_I2C_H_ */

/**
 * cam_qup_i2c_read : QUP based i2c read
 * @client    : QUP I2C client structure
 * @data      : I2C data
 * @addr_type : I2c address type
 * @data_type : I2C data type
 *
 * This API handles QUP I2C read
 */

int32_t cam_qup_i2c_read(struct i2c_client *client,
	uint32_t addr, uint32_t *data,
	enum camera_sensor_i2c_type addr_type,
	enum camera_sensor_i2c_type data_type);

/**
 * cam_qup_i2c_read_seq : QUP based I2C sequential read
 * @client    : QUP I2C client structure
 * @data      : I2C data
 * @addr_type : I2c address type
 * @num_bytes : number of bytes to read
 * This API handles QUP I2C Sequential read
 */

int32_t cam_qup_i2c_read_seq(struct i2c_client *client,
	uint32_t addr, uint8_t *data,
	enum camera_sensor_i2c_type addr_type,
	uint32_t num_byte);

/**
 * cam_qup_i2c_poll : QUP based I2C poll operation
 * @client    : QUP I2C client structure
 * @addr      : I2C address
 * @data      : I2C data
 * @data_mask : I2C data mask
 * @data_type : I2C data type
 * @addr_type : I2C addr type
 * @delay_ms  : Delay in milli seconds
 *
 * This API implements QUP based I2C poll
 */

int32_t cam_qup_i2c_poll(struct i2c_client *client,
	uint32_t addr, uint16_t data, uint16_t data_mask,
	enum camera_sensor_i2c_type addr_type,
	enum camera_sensor_i2c_type data_type,
	uint32_t delay_ms);

/**
 * cam_qup_i2c_write_table : QUP based I2C write random
 * @client        : QUP I2C client structure
 * @write_setting : I2C register settings
 *
 * This API handles QUP I2C random write
 */

int32_t cam_qup_i2c_write_table(
	struct camera_io_master *client,
	struct cam_sensor_i2c_reg_setting *write_setting);
#endif /*_CAM_SENSOR_I2C_H*/
+10 −0
Original line number Diff line number Diff line
@@ -29,6 +29,10 @@ int32_t camera_io_dev_poll(struct camera_io_master *io_master_info,
	if (io_master_info->master_type == CCI_MASTER) {
		return cam_cci_i2c_poll(io_master_info->cci_client,
			addr, data, mask, data_type, addr_type, delay_ms);
	} else if (io_master_info->master_type == I2C_MASTER) {
		return cam_qup_i2c_poll(io_master_info->client,
			addr, data, data_mask, addr_type, data_type,
			delay_ms);
	} else {
		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
			__LINE__, io_master_info->master_type);
@@ -49,6 +53,9 @@ int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
	if (io_master_info->master_type == CCI_MASTER) {
		return cam_cci_i2c_read(io_master_info->cci_client,
			addr, data, addr_type, data_type);
	} else if (io_master_info->master_type == I2C_MASTER) {
		return cam_qup_i2c_read(io_master_info->client,
			addr, data, addr_type, data_type);
	} else {
		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
			__LINE__, io_master_info->master_type);
@@ -68,6 +75,9 @@ int32_t camera_io_dev_write(struct camera_io_master *io_master_info,
	if (io_master_info->master_type == CCI_MASTER) {
		return cam_cci_i2c_write_table(io_master_info,
			write_setting);
	} else if (io_master_info->master_type == I2C_MASTER) {
		return cam_qup_i2c_write_table(io_master_info,
			write_setting);
	} else {
		pr_err("%s:%d Invalid Comm. Master:%d\n", __func__,
			__LINE__, io_master_info->master_type);
+16 −1
Original line number Diff line number Diff line
@@ -38,7 +38,7 @@ struct camera_io_master {
 * @io_master_info: I2C/SPI master information
 * @addr: I2C address
 * @data: I2C data
 * @addr_type: I2C addr type
 * @addr_type: I2C addr_type
 * @data_type: I2C data type
 *
 * This API abstracts read functionality based on master type
@@ -48,6 +48,21 @@ int32_t camera_io_dev_read(struct camera_io_master *io_master_info,
	enum camera_sensor_i2c_type addr_type,
	enum camera_sensor_i2c_type data_type);

/**
 * @io_master_info: I2C/SPI master information
 * @addr: I2C address
 * @data: I2C data
 * @addr_type: I2C addr type
 * @num_bytes: number of bytes
 *
 * This API abstracts sequential read functionality based on master type
 */
int32_t camera_io_dev_read_seq(struct camera_io_master *io_master_info,
	uint32_t addr, uint8_t *data,
	enum camera_sensor_i2c_type addr_type,
	uint32_t num_bytes);


/**
 * @io_master_info: I2C/SPI master information
 *
+361 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017, The Linux Foundation. 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 and
 * only 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.
 */

#include "cam_sensor_cmn_header.h"
#include "cam_sensor_i2c.h"
#include "cam_sensor_io.h"

#define I2C_REG_DATA_MAX       (8*1024)
#define I2C_REG_MAX_BUF_SIZE   8

static int32_t cam_qup_i2c_rxdata(
	struct i2c_client *dev_client, unsigned char *rxdata,
	enum camera_sensor_i2c_type addr_type,
	int data_length)
{
	int32_t rc = 0;
	uint16_t saddr = dev_client->addr >> 1;
	struct i2c_msg msgs[] = {
		{
			.addr  = saddr,
			.flags = 0,
			.len   = addr_type,
			.buf   = rxdata,
		},
		{
			.addr  = saddr,
			.flags = I2C_M_RD,
			.len   = data_length,
			.buf   = rxdata,
		},
	};
	rc = i2c_transfer(dev_client->adapter, msgs, 2);
	if (rc < 0)
		pr_err("%s:failed 0x%x\n", __func__, saddr);
	return rc;
}


static int32_t cam_qup_i2c_txdata(
	struct camera_io_master *dev_client, unsigned char *txdata,
	int length)
{
	int32_t rc = 0;
	uint16_t saddr = dev_client->client->addr >> 1;
	struct i2c_msg msg[] = {
		{
			.addr = saddr,
			.flags = 0,
			.len = length,
			.buf = txdata,
		 },
	};
	rc = i2c_transfer(dev_client->client->adapter, msg, 1);
	if (rc < 0)
		pr_err("%s: failed 0x%x\n", __func__, saddr);
	return rc;
}

int32_t cam_qup_i2c_read(struct i2c_client *client,
	uint32_t addr, uint32_t *data,
	enum camera_sensor_i2c_type addr_type,
	enum camera_sensor_i2c_type data_type)
{
	int32_t rc = -EINVAL;
	unsigned char *buf = NULL;

	if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
		|| addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
		|| data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
		|| data_type >= CAMERA_SENSOR_I2C_TYPE_MAX) {
		pr_err("ERR: %s Failed with addr/data_type verfication\n",
			__func__);
		return rc;
	}

	buf = kzalloc(addr_type + data_type, GFP_KERNEL);

	if (!buf)
		return -ENOMEM;

	if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
		buf[0] = addr;
	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
		buf[0] = addr >> 8;
		buf[1] = addr;
	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
		buf[0] = addr >> 16;
		buf[1] = addr >> 8;
		buf[2] = addr;
	} else {
		buf[0] = addr >> 24;
		buf[1] = addr >> 16;
		buf[2] = addr >> 8;
		buf[3] = addr;
	}

	rc = cam_qup_i2c_rxdata(client, buf, addr_type, data_type);
	if (rc < 0) {
		pr_err("%s fail\n", __func__);
		goto read_fail;
	}

	if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE)
		*data = buf[0];
	else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD)
		*data = buf[0] << 8 | buf[1];
	else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B)
		*data = buf[0] << 16 | buf[1] << 8 | buf[2];
	else
		*data = buf[0] << 24 | buf[1] << 16 |
			buf[2] << 8 | buf[3];

	CDBG("%s addr = 0x%x data: 0x%x\n", __func__, addr, *data);
read_fail:
	kfree(buf);
	buf = NULL;
	return rc;
}

int32_t cam_qup_i2c_read_seq(struct i2c_client *client,
	uint32_t addr, uint8_t *data,
	enum camera_sensor_i2c_type addr_type,
	uint32_t num_byte)
{
	int32_t rc = -EFAULT;
	unsigned char *buf = NULL;
	int i;

	if (addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
		|| addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX) {
		pr_err("ERR: %s Failed with addr_type verification\n",
			__func__);
		return rc;
	}

	if ((num_byte == 0) || (num_byte > I2C_REG_DATA_MAX)) {
		pr_err("%s: Error num_byte:0x%x max supported:0x%x\n",
			__func__, num_byte, I2C_REG_DATA_MAX);
		return rc;
	}

	buf = kzalloc(addr_type + num_byte, GFP_KERNEL);
	if (!buf)
		return -ENOMEM;

	if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
		buf[0] = addr;
	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
		buf[0] = addr >> BITS_PER_BYTE;
		buf[1] = addr;
	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
		buf[0] = addr >> 16;
		buf[1] = addr >> 8;
		buf[2] = addr;
	} else {
		buf[0] = addr >> 24;
		buf[1] = addr >> 16;
		buf[2] = addr >> 8;
		buf[3] = addr;
	}

	rc = cam_qup_i2c_rxdata(client, buf, addr_type, num_byte);
	if (rc < 0) {
		pr_err("%s fail\n", __func__);
		goto read_seq_fail;
	}

	for (i = 0; i < num_byte; i++)
		data[i] = buf[i];

read_seq_fail:
	kfree(buf);
	buf = NULL;
	return rc;
}

static int32_t cam_qup_i2c_compare(struct i2c_client *client,
	uint32_t addr, uint32_t data, uint16_t data_mask,
	enum camera_sensor_i2c_type data_type,
	enum camera_sensor_i2c_type addr_type)
{
	int32_t rc;
	uint32_t reg_data = 0;

	rc = cam_qup_i2c_read(client, addr, &reg_data,
		addr_type, data_type);
	if (rc < 0)
		return rc;

	reg_data = reg_data & 0xFFFF;
	if (data != (reg_data & ~data_mask))
		return I2C_COMPARE_MISMATCH;

	return I2C_COMPARE_MATCH;
}

int32_t cam_qup_i2c_poll(struct i2c_client *client,
	uint32_t addr, uint16_t data, uint16_t data_mask,
	enum camera_sensor_i2c_type addr_type,
	enum camera_sensor_i2c_type data_type,
	uint32_t delay_ms)
{
	int32_t rc = 0;
	int i = 0;

	if ((delay_ms > MAX_POLL_DELAY_MS) || (delay_ms == 0)) {
		pr_err("%s:%d invalid delay = %d max_delay = %d\n",
			__func__, __LINE__, delay_ms, MAX_POLL_DELAY_MS);
		return -EINVAL;
	}

	if ((addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
		|| addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
		|| data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
		|| data_type >= CAMERA_SENSOR_I2C_TYPE_MAX))
		return -EINVAL;

	for (i = 0; i < delay_ms; i++) {
		rc = cam_qup_i2c_compare(client,
			addr, data, data_mask, data_type, addr_type);
		if (rc == I2C_COMPARE_MATCH)
			return rc;

		usleep_range(1000, 1010);
	}
	/* If rc is MISMATCH then read is successful but poll is failure */
	if (rc == I2C_COMPARE_MISMATCH)
		pr_err("%s:%d poll failed rc=%d(non-fatal)\n",
			__func__, __LINE__, rc);
	if (rc < 0)
		pr_err("%s:%d poll failed rc=%d\n", __func__, __LINE__, rc);

	return rc;
}

static int32_t cam_qup_i2c_write(struct camera_io_master *client,
	struct cam_sensor_i2c_reg_array *reg_setting,
	enum camera_sensor_i2c_type addr_type,
	enum camera_sensor_i2c_type data_type)
{
	int32_t rc = 0;
	unsigned char buf[I2C_REG_MAX_BUF_SIZE];
	uint8_t len = 0;

	CDBG("%s reg addr = 0x%x data type: %d\n",
			  __func__, reg_setting->reg_addr, data_type);
	if (addr_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
		buf[0] = reg_setting->reg_addr;
		CDBG("%s byte %d: 0x%x\n", __func__,
			len, buf[len]);
		len = 1;
	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
		buf[0] = reg_setting->reg_addr >> 8;
		buf[1] = reg_setting->reg_addr;
		CDBG("%s byte %d: 0x%x\n", __func__,
			len, buf[len]);
		CDBG("%s byte %d: 0x%x\n", __func__,
			len+1, buf[len+1]);
		len = 2;
	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_3B) {
		buf[0] = reg_setting->reg_addr >> 16;
		buf[1] = reg_setting->reg_addr >> 8;
		buf[2] = reg_setting->reg_addr;
		len = 3;
	} else if (addr_type == CAMERA_SENSOR_I2C_TYPE_DWORD) {
		buf[0] = reg_setting->reg_addr >> 24;
		buf[1] = reg_setting->reg_addr >> 16;
		buf[2] = reg_setting->reg_addr >> 8;
		buf[3] = reg_setting->reg_addr;
		len = 4;
	} else {
		pr_err("%s: Invalid I2C addr type\n", __func__);
		return -EINVAL;
	}

	CDBG("Data: 0x%x\n", reg_setting->reg_data);
	if (data_type == CAMERA_SENSOR_I2C_TYPE_BYTE) {
		buf[len] = reg_setting->reg_data;
		CDBG("Byte %d: 0x%x\n", len, buf[len]);
		len += 1;
	} else if (data_type == CAMERA_SENSOR_I2C_TYPE_WORD) {
		buf[len] = reg_setting->reg_data >> 8;
		buf[len+1] = reg_setting->reg_data;
		CDBG("Byte %d: 0x%x\n", len, buf[len]);
		CDBG("Byte %d: 0x%x\n", len+1, buf[len+1]);
		len += 2;
	} else if (data_type == CAMERA_SENSOR_I2C_TYPE_3B) {
		buf[len] = reg_setting->reg_data >> 16;
		buf[len + 1] = reg_setting->reg_data >> 8;
		buf[len + 2] = reg_setting->reg_data;
		CDBG("Byte %d: 0x%x\n", len, buf[len]);
		CDBG("Byte %d: 0x%x\n", len+1, buf[len+1]);
		CDBG("Byte %d: 0x%x\n", len+2, buf[len+2]);
		len += 3;
	} else if (data_type == CAMERA_SENSOR_I2C_TYPE_DWORD) {
		buf[len] = reg_setting->reg_data >> 24;
		buf[len + 1] = reg_setting->reg_data >> 16;
		buf[len + 2] = reg_setting->reg_data >> 8;
		buf[len + 3] = reg_setting->reg_data;
		CDBG("Byte %d: 0x%x\n", len, buf[len]);
		CDBG("Byte %d: 0x%x\n", len+1, buf[len+1]);
		CDBG("Byte %d: 0x%x\n", len+2, buf[len+2]);
		CDBG("Byte %d: 0x%x\n", len+3, buf[len+3]);
		len += 4;
	} else {
		pr_err("%s: Invalid Data Type\n", __func__);
		return -EINVAL;
	}

	rc = cam_qup_i2c_txdata(client, buf, len);
	if (rc < 0)
		pr_err("%s fail\n", __func__);
	return rc;
}

int32_t cam_qup_i2c_write_table(struct camera_io_master *client,
	struct cam_sensor_i2c_reg_setting *write_setting)
{
	int i;
	int32_t rc = -EINVAL;
	struct cam_sensor_i2c_reg_array *reg_setting;

	if (!client || !write_setting)
		return rc;

	if ((write_setting->addr_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
		|| write_setting->addr_type >= CAMERA_SENSOR_I2C_TYPE_MAX
		|| (write_setting->data_type <= CAMERA_SENSOR_I2C_TYPE_INVALID
		|| write_setting->data_type >= CAMERA_SENSOR_I2C_TYPE_MAX)))
		return rc;

	reg_setting = write_setting->reg_setting;

	for (i = 0; i < write_setting->size; i++) {
		CDBG("%s addr 0x%x data 0x%x\n", __func__,
			reg_setting->reg_addr, reg_setting->reg_data);

		rc = cam_qup_i2c_write(client, reg_setting,
			write_setting->addr_type, write_setting->data_type);
		if (rc < 0)
			break;
		reg_setting++;
	}

	if (write_setting->delay > 20)
		msleep(write_setting->delay);
	else if (write_setting->delay)
		usleep_range(write_setting->delay * 1000, (write_setting->delay
			* 1000) + 1000);

	return rc;
}