mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-23 17:55:05 +03:00
drivers: media: CDI: Add IO Expander support
Add IO Expander support in CDI Dev to control the FRSYNC multiplexer with the speicific platform Bug 3582660 Change-Id: I3ee376e7a0bccabcfa16efb228879d4df0d65748 Signed-off-by: Junghyun Kim <juskim@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2727256 Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2824551 Reviewed-by: Frank Chen <frankc@nvidia.com> Reviewed-by: Shiva Dubey <sdubey@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
eb1d8b3b58
commit
9269dac3ec
@@ -5,6 +5,7 @@
|
|||||||
#define __CDI_DEV_PRIV_H__
|
#define __CDI_DEV_PRIV_H__
|
||||||
|
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
|
#include "cdi-tca-priv.h"
|
||||||
|
|
||||||
#define MAX_POWER_LINKS_PER_BLOCK (4U)
|
#define MAX_POWER_LINKS_PER_BLOCK (4U)
|
||||||
|
|
||||||
@@ -32,6 +33,8 @@ struct cdi_dev_info {
|
|||||||
u8 cam_pwr_method;
|
u8 cam_pwr_method;
|
||||||
u8 cam_pwr_i2c_addr;
|
u8 cam_pwr_i2c_addr;
|
||||||
struct max20087_priv max20087;
|
struct max20087_priv max20087;
|
||||||
|
struct tca9539_priv tca9539;
|
||||||
|
u8 cim_ver; /* 1 - P3714 A01, 2 - P3714 A02/A03 */
|
||||||
};
|
};
|
||||||
|
|
||||||
int cdi_dev_raw_rd(struct cdi_dev_info *info, unsigned int offset,
|
int cdi_dev_raw_rd(struct cdi_dev_info *info, unsigned int offset,
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
#include <linux/cdev.h>
|
#include <linux/cdev.h>
|
||||||
#include <media/cdi-mgr.h>
|
#include <media/cdi-mgr.h>
|
||||||
|
#include "cdi-tca-priv.h"
|
||||||
|
|
||||||
#define CDI_MGR_STOP_GPIO_INTR_EVENT_WAIT (~(0u))
|
#define CDI_MGR_STOP_GPIO_INTR_EVENT_WAIT (~(0u))
|
||||||
#define CDI_MGR_TCA9539_REGISTER_COUNT (8)
|
#define CDI_MGR_TCA9539_REGISTER_COUNT (8)
|
||||||
@@ -24,17 +25,6 @@ struct cam_gpio_config {
|
|||||||
int gpio_intr_irq;
|
int gpio_intr_irq;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tca9539_priv {
|
|
||||||
struct i2c_adapter *adap;
|
|
||||||
int bus;
|
|
||||||
u32 addr;
|
|
||||||
u32 reg_len;
|
|
||||||
u32 dat_len;
|
|
||||||
u8 init_val[12];
|
|
||||||
u32 power_port;
|
|
||||||
bool enable;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct cdi_mgr_priv {
|
struct cdi_mgr_priv {
|
||||||
struct device *pdev; /* parent device */
|
struct device *pdev; /* parent device */
|
||||||
struct device *dev; /* this device */
|
struct device *dev; /* this device */
|
||||||
@@ -65,7 +55,7 @@ struct cdi_mgr_priv {
|
|||||||
uint32_t gpio_count;
|
uint32_t gpio_count;
|
||||||
uint32_t err_irq_recvd_status_mask;
|
uint32_t err_irq_recvd_status_mask;
|
||||||
bool stop_err_irq_wait;
|
bool stop_err_irq_wait;
|
||||||
u8 cim_ver; /* 1 - P3714 A01, 2 - P3714 A02 */
|
u8 cim_ver; /* 1 - P3714 A01, 2 - P3714 A02/A03 */
|
||||||
u32 cim_frsync[3]; /* FRSYNC source selection for each muxer */
|
u32 cim_frsync[3]; /* FRSYNC source selection for each muxer */
|
||||||
u8 pre_suspend_tca9539_regvals[CDI_MGR_TCA9539_REGISTER_COUNT];
|
u8 pre_suspend_tca9539_regvals[CDI_MGR_TCA9539_REGISTER_COUNT];
|
||||||
};
|
};
|
||||||
|
|||||||
122
drivers/media/platform/tegra/cdi/cdi-tca-priv.h
Normal file
122
drivers/media/platform/tegra/cdi/cdi-tca-priv.h
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
// SPDX-License-Identifier: GPL-2.0
|
||||||
|
// Copyright (c) 2022, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
|
||||||
|
|
||||||
|
#ifndef __CDI_TCA9539_PRIV_H__
|
||||||
|
#define __CDI_TCA9539_PRIV_H__
|
||||||
|
|
||||||
|
/* i2c payload size is only 12 bit */
|
||||||
|
#define MAX_MSG_SIZE (0xFFF - 1)
|
||||||
|
|
||||||
|
struct tca9539_priv {
|
||||||
|
struct i2c_adapter *adap;
|
||||||
|
int bus;
|
||||||
|
u32 addr;
|
||||||
|
u32 reg_len;
|
||||||
|
u32 dat_len;
|
||||||
|
u8 init_val[12];
|
||||||
|
u32 power_port;
|
||||||
|
bool enable;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int tca9539_raw_wr(
|
||||||
|
struct device *dev, struct tca9539_priv *tca9539, unsigned int offset, u8 val)
|
||||||
|
{
|
||||||
|
int ret = -ENODEV;
|
||||||
|
u8 *buf_start = NULL;
|
||||||
|
struct i2c_msg *i2cmsg;
|
||||||
|
unsigned int num_msgs = 0, total_size, i;
|
||||||
|
u8 data[3];
|
||||||
|
size_t size = 1;
|
||||||
|
|
||||||
|
dev_dbg(dev, "%s\n", __func__);
|
||||||
|
|
||||||
|
if (tca9539->reg_len == 2) {
|
||||||
|
data[0] = (u8)((offset >> 8) & 0xff);
|
||||||
|
data[1] = (u8)(offset & 0xff);
|
||||||
|
data[2] = val;
|
||||||
|
size += 2;
|
||||||
|
} else if (tca9539->reg_len == 1) {
|
||||||
|
data[0] = (u8)(offset & 0xff);
|
||||||
|
data[1] = val;
|
||||||
|
size += 1;
|
||||||
|
} else if ((tca9539->reg_len == 0) ||
|
||||||
|
(tca9539->reg_len > 3)) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
num_msgs = size / MAX_MSG_SIZE;
|
||||||
|
num_msgs += (size % MAX_MSG_SIZE) ? 1 : 0;
|
||||||
|
|
||||||
|
i2cmsg = kzalloc((sizeof(struct i2c_msg)*num_msgs), GFP_KERNEL);
|
||||||
|
if (!i2cmsg) {
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf_start = data;
|
||||||
|
total_size = size;
|
||||||
|
|
||||||
|
dev_dbg(dev, "%s: num_msgs: %d\n", __func__, num_msgs);
|
||||||
|
for (i = 0; i < num_msgs; i++) {
|
||||||
|
i2cmsg[i].addr = tca9539->addr;
|
||||||
|
i2cmsg[i].buf = (__u8 *)buf_start;
|
||||||
|
|
||||||
|
if (i > 0)
|
||||||
|
i2cmsg[i].flags = I2C_M_NOSTART;
|
||||||
|
else
|
||||||
|
i2cmsg[i].flags = 0;
|
||||||
|
|
||||||
|
if (total_size > MAX_MSG_SIZE) {
|
||||||
|
i2cmsg[i].len = MAX_MSG_SIZE;
|
||||||
|
buf_start += MAX_MSG_SIZE;
|
||||||
|
total_size -= MAX_MSG_SIZE;
|
||||||
|
} else {
|
||||||
|
i2cmsg[i].len = total_size;
|
||||||
|
}
|
||||||
|
dev_dbg(dev, "%s: addr:%x buf:%p, flags:%u len:%u\n",
|
||||||
|
__func__, i2cmsg[i].addr, (void *)i2cmsg[i].buf,
|
||||||
|
i2cmsg[i].flags, i2cmsg[i].len);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = i2c_transfer(tca9539->adap, i2cmsg, num_msgs);
|
||||||
|
if (ret > 0)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
kfree(i2cmsg);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tca9539_raw_rd(
|
||||||
|
struct device *dev, struct tca9539_priv *tca9539, unsigned int offset, u8 *val)
|
||||||
|
{
|
||||||
|
int ret = -ENODEV;
|
||||||
|
u8 data[2];
|
||||||
|
size_t size = 1;
|
||||||
|
struct i2c_msg i2cmsg[2];
|
||||||
|
|
||||||
|
dev_dbg(dev, "%s\n", __func__);
|
||||||
|
|
||||||
|
if (tca9539->reg_len == 2) {
|
||||||
|
data[0] = (u8)((offset >> 8) & 0xff);
|
||||||
|
data[1] = (u8)(offset & 0xff);
|
||||||
|
} else if (tca9539->reg_len == 1)
|
||||||
|
data[0] = (u8)(offset & 0xff);
|
||||||
|
|
||||||
|
i2cmsg[0].addr = tca9539->addr;
|
||||||
|
i2cmsg[0].len = tca9539->reg_len;
|
||||||
|
i2cmsg[0].buf = (__u8 *)data;
|
||||||
|
i2cmsg[0].flags = I2C_M_NOSTART;
|
||||||
|
|
||||||
|
i2cmsg[1].addr = tca9539->addr;
|
||||||
|
i2cmsg[1].flags = I2C_M_RD;
|
||||||
|
i2cmsg[1].len = size;
|
||||||
|
i2cmsg[1].buf = (__u8 *)val;
|
||||||
|
|
||||||
|
ret = i2c_transfer(tca9539->adap, i2cmsg, 2);
|
||||||
|
if (ret > 0)
|
||||||
|
ret = 0;
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __CDI_TCA9539_PRIV_H__ */
|
||||||
|
|
||||||
@@ -394,6 +394,81 @@ static int cdi_dev_get_pwr_info(
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tca9539_wr(
|
||||||
|
struct cdi_dev_info *info, unsigned int offset, u8 val)
|
||||||
|
{
|
||||||
|
int ret = -ENODEV;
|
||||||
|
|
||||||
|
dev_dbg(info->dev, "%s\n", __func__);
|
||||||
|
mutex_lock(&info->mutex);
|
||||||
|
|
||||||
|
ret = tca9539_raw_wr(info->dev, &info->tca9539, offset, val);
|
||||||
|
|
||||||
|
mutex_unlock(&info->mutex);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tca9539_rd(
|
||||||
|
struct cdi_dev_info *info, unsigned int offset, u8 *val)
|
||||||
|
{
|
||||||
|
int ret = -ENODEV;
|
||||||
|
|
||||||
|
dev_dbg(info->dev, "%s\n", __func__);
|
||||||
|
mutex_lock(&info->mutex);
|
||||||
|
|
||||||
|
ret = tca9539_raw_rd(info->dev, &info->tca9539, offset, val);
|
||||||
|
|
||||||
|
mutex_unlock(&info->mutex);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int cdi_dev_set_fsync_mux(
|
||||||
|
struct cdi_dev_info *info,
|
||||||
|
void __user *arg)
|
||||||
|
{
|
||||||
|
u8 val, shift;
|
||||||
|
struct cdi_dev_fsync_mux fsync_mux;
|
||||||
|
|
||||||
|
if (copy_from_user(&fsync_mux, arg, sizeof(fsync_mux))) {
|
||||||
|
dev_err(info->dev,
|
||||||
|
"%s: failed to copy from user\n", __func__);
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info->cim_ver == 2U) {
|
||||||
|
/* P01:P00 for the camera group B. cam_grp 1.
|
||||||
|
* P03:P02 for the camera group C. cam_grp 2.
|
||||||
|
* P05:P04 for the camera group D. cam_grp 3.
|
||||||
|
*/
|
||||||
|
if ((fsync_mux.cam_grp > 0U) && (fsync_mux.cam_grp < 4U)) {
|
||||||
|
if (tca9539_rd(info, 0x02, &val) != 0)
|
||||||
|
return -EFAULT;
|
||||||
|
switch (fsync_mux.cam_grp) {
|
||||||
|
case 1U:
|
||||||
|
shift = 0U;
|
||||||
|
break;
|
||||||
|
case 2U:
|
||||||
|
shift = 2U;
|
||||||
|
break;
|
||||||
|
case 3U:
|
||||||
|
shift = 4U;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
shift = 0U;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
val &= ~(0x3 << shift);
|
||||||
|
val |= (fsync_mux.mux_sel << shift);
|
||||||
|
if (tca9539_wr(info, 0x02, val) != 0)
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static long cdi_dev_ioctl(struct file *file,
|
static long cdi_dev_ioctl(struct file *file,
|
||||||
unsigned int cmd, unsigned long arg)
|
unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
@@ -411,6 +486,9 @@ static long cdi_dev_ioctl(struct file *file,
|
|||||||
case CDI_DEV_IOCTL_GET_PWR_INFO:
|
case CDI_DEV_IOCTL_GET_PWR_INFO:
|
||||||
err = cdi_dev_get_pwr_info(info, (void __user *)arg);
|
err = cdi_dev_get_pwr_info(info, (void __user *)arg);
|
||||||
break;
|
break;
|
||||||
|
case CDI_DEV_IOCTL_FRSYNC_MUX:
|
||||||
|
err = cdi_dev_set_fsync_mux(info, (void __user *)arg);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
dev_dbg(info->dev, "%s: invalid cmd %x\n", __func__, cmd);
|
dev_dbg(info->dev, "%s: invalid cmd %x\n", __func__, cmd);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
@@ -453,6 +531,38 @@ static const struct file_operations cdi_dev_fileops = {
|
|||||||
.release = cdi_dev_release,
|
.release = cdi_dev_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void cdi_dev_get_cim_ver(struct device_node *np, struct cdi_dev_info *info)
|
||||||
|
{
|
||||||
|
int err = 0;
|
||||||
|
struct device_node *child = NULL;
|
||||||
|
struct device_node *cim = NULL;
|
||||||
|
const char *cim_ver;
|
||||||
|
|
||||||
|
child = of_get_parent(np);
|
||||||
|
if (child != NULL) {
|
||||||
|
cim = of_get_compatible_child(child,
|
||||||
|
"nvidia,cim_ver");
|
||||||
|
if (cim != NULL) {
|
||||||
|
err = of_property_read_string(cim,
|
||||||
|
"cim_ver",
|
||||||
|
&cim_ver);
|
||||||
|
if (!err) {
|
||||||
|
if (!strncmp(cim_ver,
|
||||||
|
"cim_ver_a01",
|
||||||
|
sizeof("cim_ver_a01"))) {
|
||||||
|
dev_info(info->dev,
|
||||||
|
"CIM A01\n");
|
||||||
|
info->cim_ver = 1U;
|
||||||
|
} else {
|
||||||
|
dev_info(info->dev,
|
||||||
|
"CIM A02\n");
|
||||||
|
info->cim_ver = 2U;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int cdi_dev_probe(struct i2c_client *client,
|
static int cdi_dev_probe(struct i2c_client *client,
|
||||||
const struct i2c_device_id *id)
|
const struct i2c_device_id *id)
|
||||||
{
|
{
|
||||||
@@ -460,6 +570,7 @@ static int cdi_dev_probe(struct i2c_client *client,
|
|||||||
struct cdi_mgr_priv *cdi_mgr = NULL;
|
struct cdi_mgr_priv *cdi_mgr = NULL;
|
||||||
struct device *pdev;
|
struct device *pdev;
|
||||||
struct device_node *child = NULL, *child_max20087 = NULL;
|
struct device_node *child = NULL, *child_max20087 = NULL;
|
||||||
|
struct device_node *child_tca9539 = NULL;
|
||||||
int err;
|
int err;
|
||||||
int numLinks = 0;
|
int numLinks = 0;
|
||||||
int i;
|
int i;
|
||||||
@@ -483,7 +594,10 @@ static int cdi_dev_probe(struct i2c_client *client,
|
|||||||
dev_notice(&client->dev, "%s NO platform data\n", __func__);
|
dev_notice(&client->dev, "%s NO platform data\n", __func__);
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->pdata->np != NULL) {
|
if (info->pdata->np != NULL) {
|
||||||
|
cdi_dev_get_cim_ver(info->pdata->np, info);
|
||||||
|
|
||||||
child = of_get_child_by_name(info->pdata->np,
|
child = of_get_child_by_name(info->pdata->np,
|
||||||
"pwr_ctrl");
|
"pwr_ctrl");
|
||||||
if (child != NULL) {
|
if (child != NULL) {
|
||||||
@@ -553,6 +667,68 @@ static int cdi_dev_probe(struct i2c_client *client,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (info->cim_ver == 2U) {
|
||||||
|
/* get the I/O expander information */
|
||||||
|
child_tca9539 = of_get_child_by_name(child, "tca9539");
|
||||||
|
if (child_tca9539 != NULL) {
|
||||||
|
err = of_property_read_u32(child_tca9539, "i2c-bus",
|
||||||
|
&info->tca9539.bus);
|
||||||
|
if (err) {
|
||||||
|
dev_err(info->dev,
|
||||||
|
"%s: Failed to get I2C bus number, ERROR %d\n",
|
||||||
|
__func__, err);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
err = of_property_read_u32(child_tca9539, "addr",
|
||||||
|
&info->tca9539.addr);
|
||||||
|
if (err || !info->tca9539.addr) {
|
||||||
|
dev_err(info->dev,
|
||||||
|
"%s: ERROR %d addr = %d\n",
|
||||||
|
__func__, err,
|
||||||
|
info->tca9539.addr);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
err = of_property_read_u32(child_tca9539, "reg_len",
|
||||||
|
&info->tca9539.reg_len);
|
||||||
|
if (err || !info->tca9539.reg_len) {
|
||||||
|
dev_err(info->dev,
|
||||||
|
"%s: ERROR %d reg_len = %d\n",
|
||||||
|
__func__, err,
|
||||||
|
info->tca9539.reg_len);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
err = of_property_read_u32(child_tca9539, "dat_len",
|
||||||
|
&info->tca9539.dat_len);
|
||||||
|
if (err || !info->tca9539.dat_len) {
|
||||||
|
dev_err(info->dev,
|
||||||
|
"%s: ERROR %d dat_len = %d\n",
|
||||||
|
__func__, err,
|
||||||
|
info->tca9539.dat_len);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
err = of_property_read_u32(child_tca9539->parent,
|
||||||
|
"power_port",
|
||||||
|
&info->tca9539.power_port);
|
||||||
|
if (err) {
|
||||||
|
dev_err(info->dev,
|
||||||
|
"%s: ERROR %d power_port = %d\n",
|
||||||
|
__func__, err,
|
||||||
|
info->tca9539.power_port);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
|
||||||
|
info->tca9539.reg_len /= 8;
|
||||||
|
info->tca9539.dat_len /= 8;
|
||||||
|
info->tca9539.enable = 1;
|
||||||
|
info->tca9539.adap = i2c_get_adapter(info->tca9539.bus);
|
||||||
|
if (!info->tca9539.adap) {
|
||||||
|
dev_err(info->dev, "%s no such i2c bus %d\n",
|
||||||
|
__func__, info->tca9539.bus);
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->pdata->reg_bits)
|
if (info->pdata->reg_bits)
|
||||||
|
|||||||
@@ -146,107 +146,30 @@ static int pwr_off_set(void *data, u64 val)
|
|||||||
|
|
||||||
DEFINE_SIMPLE_ATTRIBUTE(pwr_off_fops, pwr_off_get, pwr_off_set, "0x%02llx\n");
|
DEFINE_SIMPLE_ATTRIBUTE(pwr_off_fops, pwr_off_get, pwr_off_set, "0x%02llx\n");
|
||||||
|
|
||||||
static int tca9539_raw_wr(
|
static int tca9539_wr(
|
||||||
struct cdi_mgr_priv *info, unsigned int offset, u8 val)
|
struct cdi_mgr_priv *info, unsigned int offset, u8 val)
|
||||||
{
|
{
|
||||||
int ret = -ENODEV;
|
int ret = -ENODEV;
|
||||||
u8 *buf_start = NULL;
|
|
||||||
struct i2c_msg *i2cmsg;
|
|
||||||
unsigned int num_msgs = 0, total_size, i;
|
|
||||||
u8 data[3];
|
|
||||||
size_t size = 1;
|
|
||||||
|
|
||||||
dev_dbg(info->dev, "%s\n", __func__);
|
dev_dbg(info->dev, "%s\n", __func__);
|
||||||
mutex_lock(&info->mutex);
|
mutex_lock(&info->mutex);
|
||||||
|
|
||||||
if (info->tca9539.reg_len == 2) {
|
ret = tca9539_raw_wr(info->dev, &info->tca9539, offset, val);
|
||||||
data[0] = (u8)((offset >> 8) & 0xff);
|
|
||||||
data[1] = (u8)(offset & 0xff);
|
|
||||||
data[2] = val;
|
|
||||||
size += 2;
|
|
||||||
} else if (info->tca9539.reg_len == 1) {
|
|
||||||
data[0] = (u8)(offset & 0xff);
|
|
||||||
data[1] = val;
|
|
||||||
size += 1;
|
|
||||||
} else if ((info->tca9539.reg_len == 0) ||
|
|
||||||
(info->tca9539.reg_len > 3)) {
|
|
||||||
mutex_unlock(&info->mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
num_msgs = size / MAX_MSG_SIZE;
|
|
||||||
num_msgs += (size % MAX_MSG_SIZE) ? 1 : 0;
|
|
||||||
|
|
||||||
i2cmsg = kzalloc((sizeof(struct i2c_msg)*num_msgs), GFP_KERNEL);
|
|
||||||
if (!i2cmsg) {
|
|
||||||
mutex_unlock(&info->mutex);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
buf_start = data;
|
|
||||||
total_size = size;
|
|
||||||
|
|
||||||
dev_dbg(info->dev, "%s: num_msgs: %d\n", __func__, num_msgs);
|
|
||||||
for (i = 0; i < num_msgs; i++) {
|
|
||||||
i2cmsg[i].addr = info->tca9539.addr;
|
|
||||||
i2cmsg[i].buf = (__u8 *)buf_start;
|
|
||||||
|
|
||||||
if (i > 0)
|
|
||||||
i2cmsg[i].flags = I2C_M_NOSTART;
|
|
||||||
else
|
|
||||||
i2cmsg[i].flags = 0;
|
|
||||||
|
|
||||||
if (total_size > MAX_MSG_SIZE) {
|
|
||||||
i2cmsg[i].len = MAX_MSG_SIZE;
|
|
||||||
buf_start += MAX_MSG_SIZE;
|
|
||||||
total_size -= MAX_MSG_SIZE;
|
|
||||||
} else {
|
|
||||||
i2cmsg[i].len = total_size;
|
|
||||||
}
|
|
||||||
dev_dbg(info->dev, "%s: addr:%x buf:%p, flags:%u len:%u\n",
|
|
||||||
__func__, i2cmsg[i].addr, (void *)i2cmsg[i].buf,
|
|
||||||
i2cmsg[i].flags, i2cmsg[i].len);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = i2c_transfer(info->tca9539.adap, i2cmsg, num_msgs);
|
|
||||||
if (ret > 0)
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
kfree(i2cmsg);
|
|
||||||
mutex_unlock(&info->mutex);
|
mutex_unlock(&info->mutex);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tca9539_raw_rd(
|
static int tca9539_rd(
|
||||||
struct cdi_mgr_priv *info, unsigned int offset, u8 *val)
|
struct cdi_mgr_priv *info, unsigned int offset, u8 *val)
|
||||||
{
|
{
|
||||||
int ret = -ENODEV;
|
int ret = -ENODEV;
|
||||||
u8 data[2];
|
|
||||||
size_t size = 1;
|
|
||||||
struct i2c_msg i2cmsg[2];
|
|
||||||
|
|
||||||
dev_dbg(info->dev, "%s\n", __func__);
|
dev_dbg(info->dev, "%s\n", __func__);
|
||||||
mutex_lock(&info->mutex);
|
mutex_lock(&info->mutex);
|
||||||
|
|
||||||
if (info->tca9539.reg_len == 2) {
|
ret = tca9539_raw_rd(info->dev, &info->tca9539, offset, val);
|
||||||
data[0] = (u8)((offset >> 8) & 0xff);
|
|
||||||
data[1] = (u8)(offset & 0xff);
|
|
||||||
} else if (info->tca9539.reg_len == 1)
|
|
||||||
data[0] = (u8)(offset & 0xff);
|
|
||||||
|
|
||||||
i2cmsg[0].addr = info->tca9539.addr;
|
|
||||||
i2cmsg[0].len = info->tca9539.reg_len;
|
|
||||||
i2cmsg[0].buf = (__u8 *)data;
|
|
||||||
i2cmsg[0].flags = I2C_M_NOSTART;
|
|
||||||
|
|
||||||
i2cmsg[1].addr = info->tca9539.addr;
|
|
||||||
i2cmsg[1].flags = I2C_M_RD;
|
|
||||||
i2cmsg[1].len = size;
|
|
||||||
i2cmsg[1].buf = (__u8 *)val;
|
|
||||||
|
|
||||||
ret = i2c_transfer(info->tca9539.adap, i2cmsg, 2);
|
|
||||||
if (ret > 0)
|
|
||||||
ret = 0;
|
|
||||||
mutex_unlock(&info->mutex);
|
mutex_unlock(&info->mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
@@ -901,16 +824,16 @@ static int cdi_mgr_open(struct inode *inode, struct file *file)
|
|||||||
"%s: failed to wait for the semaphore\n",
|
"%s: failed to wait for the semaphore\n",
|
||||||
__func__);
|
__func__);
|
||||||
if (cdi_mgr->cim_ver == 1U) { /* P3714 A01 */
|
if (cdi_mgr->cim_ver == 1U) { /* P3714 A01 */
|
||||||
if (tca9539_raw_rd(cdi_mgr, 0x02, &val) != 0)
|
if (tca9539_rd(cdi_mgr, 0x02, &val) != 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
val |= (0x10 << cdi_mgr->tca9539.power_port);
|
val |= (0x10 << cdi_mgr->tca9539.power_port);
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x02, val) != 0)
|
if (tca9539_wr(cdi_mgr, 0x02, val) != 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
} else if (cdi_mgr->cim_ver == 2U) { /* P3714 A02 */
|
} else if (cdi_mgr->cim_ver == 2U) { /* P3714 A02 */
|
||||||
if (tca9539_raw_rd(cdi_mgr, 0x03, &val) != 0)
|
if (tca9539_rd(cdi_mgr, 0x03, &val) != 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
val |= (0x1 << cdi_mgr->tca9539.power_port);
|
val |= (0x1 << cdi_mgr->tca9539.power_port);
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x03, val) != 0)
|
if (tca9539_wr(cdi_mgr, 0x03, val) != 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
up(&tca9539_sem);
|
up(&tca9539_sem);
|
||||||
@@ -933,16 +856,16 @@ static int cdi_mgr_release(struct inode *inode, struct file *file)
|
|||||||
"%s: failed to wait for the semaphore\n",
|
"%s: failed to wait for the semaphore\n",
|
||||||
__func__);
|
__func__);
|
||||||
if (cdi_mgr->cim_ver == 1U) { /* P3714 A01 */
|
if (cdi_mgr->cim_ver == 1U) { /* P3714 A01 */
|
||||||
if (tca9539_raw_rd(cdi_mgr, 0x02, &val) != 0)
|
if (tca9539_rd(cdi_mgr, 0x02, &val) != 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
val &= ~(0x10 << cdi_mgr->tca9539.power_port);
|
val &= ~(0x10 << cdi_mgr->tca9539.power_port);
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x02, val) != 0)
|
if (tca9539_wr(cdi_mgr, 0x02, val) != 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
} else if (cdi_mgr->cim_ver == 2U) { /* P3714 A02 */
|
} else if (cdi_mgr->cim_ver == 2U) { /* P3714 A02 */
|
||||||
if (tca9539_raw_rd(cdi_mgr, 0x03, &val) != 0)
|
if (tca9539_rd(cdi_mgr, 0x03, &val) != 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
val &= ~(0x1 << cdi_mgr->tca9539.power_port);
|
val &= ~(0x1 << cdi_mgr->tca9539.power_port);
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x03, val) != 0)
|
if (tca9539_wr(cdi_mgr, 0x03, val) != 0)
|
||||||
return -EFAULT;
|
return -EFAULT;
|
||||||
}
|
}
|
||||||
up(&tca9539_sem);
|
up(&tca9539_sem);
|
||||||
@@ -1242,7 +1165,7 @@ static int cdi_mgr_suspend(struct device *dev)
|
|||||||
if (cdi_mgr->tca9539.enable) {
|
if (cdi_mgr->tca9539.enable) {
|
||||||
reg_addr = CDI_MGR_TCA9539_BASE_REG_ADDR;
|
reg_addr = CDI_MGR_TCA9539_BASE_REG_ADDR;
|
||||||
while (reg_addr < CDI_MGR_TCA9539_REGISTER_COUNT) {
|
while (reg_addr < CDI_MGR_TCA9539_REGISTER_COUNT) {
|
||||||
rc = tca9539_raw_rd(cdi_mgr, reg_addr,
|
rc = tca9539_rd(cdi_mgr, reg_addr,
|
||||||
&cdi_mgr->pre_suspend_tca9539_regvals[reg_addr]);
|
&cdi_mgr->pre_suspend_tca9539_regvals[reg_addr]);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
dev_err(dev, "%s: tca9539_raw_rd failed reading reg[0x%x]\n",
|
dev_err(dev, "%s: tca9539_raw_rd failed reading reg[0x%x]\n",
|
||||||
@@ -1276,7 +1199,7 @@ static int cdi_mgr_resume(struct device *dev)
|
|||||||
if (cdi_mgr->tca9539.enable) {
|
if (cdi_mgr->tca9539.enable) {
|
||||||
reg_addr = CDI_MGR_TCA9539_BASE_REG_ADDR;
|
reg_addr = CDI_MGR_TCA9539_BASE_REG_ADDR;
|
||||||
while (reg_addr < CDI_MGR_TCA9539_REGISTER_COUNT) {
|
while (reg_addr < CDI_MGR_TCA9539_REGISTER_COUNT) {
|
||||||
rc = tca9539_raw_wr(cdi_mgr, reg_addr,
|
rc = tca9539_wr(cdi_mgr, reg_addr,
|
||||||
cdi_mgr->pre_suspend_tca9539_regvals[reg_addr]);
|
cdi_mgr->pre_suspend_tca9539_regvals[reg_addr]);
|
||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
dev_err(dev, "%s: tca9539_raw_wr failed setting reg[0x%x] = 0x%x\n",
|
dev_err(dev, "%s: tca9539_raw_wr failed setting reg[0x%x] = 0x%x\n",
|
||||||
@@ -1689,27 +1612,27 @@ static int cdi_mgr_probe(struct platform_device *pdev)
|
|||||||
/* the registers in TCA9539 */
|
/* the registers in TCA9539 */
|
||||||
/* Use the IO expander to control PWDN signals */
|
/* Use the IO expander to control PWDN signals */
|
||||||
if (cdi_mgr->cim_ver == 1U) { /* P3714 A01 */
|
if (cdi_mgr->cim_ver == 1U) { /* P3714 A01 */
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x6, 0x0E) != 0) {
|
if (tca9539_wr(cdi_mgr, 0x6, 0x0E) != 0) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"%s: ERR %d: TCA9539: Failed to select PWDN signal source\n",
|
"%s: ERR %d: TCA9539: Failed to select PWDN signal source\n",
|
||||||
__func__, err);
|
__func__, err);
|
||||||
goto err_probe;
|
goto err_probe;
|
||||||
}
|
}
|
||||||
/* Output low for AGGA/B/C/D_PWRDN */
|
/* Output low for AGGA/B/C/D_PWRDN */
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x2, 0x0E) != 0) {
|
if (tca9539_wr(cdi_mgr, 0x2, 0x0E) != 0) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"%s: ERR %d: TCA9539: Failed to set the output level\n",
|
"%s: ERR %d: TCA9539: Failed to set the output level\n",
|
||||||
__func__, err);
|
__func__, err);
|
||||||
goto err_probe;
|
goto err_probe;
|
||||||
}
|
}
|
||||||
} else if (cdi_mgr->cim_ver == 2U) { /* P3714 A02 */
|
} else if (cdi_mgr->cim_ver == 2U) { /* P3714 A02 */
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x6, 0xC0) != 0) {
|
if (tca9539_wr(cdi_mgr, 0x6, 0xC0) != 0) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"%s: ERR %d: TCA9539: Failed to select FS selection signal source\n",
|
"%s: ERR %d: TCA9539: Failed to select FS selection signal source\n",
|
||||||
__func__, err);
|
__func__, err);
|
||||||
goto err_probe;
|
goto err_probe;
|
||||||
}
|
}
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x7, 0x70) != 0) {
|
if (tca9539_wr(cdi_mgr, 0x7, 0x70) != 0) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"%s: ERR %d: TCA9539: Failed to select PWDN signal source\n",
|
"%s: ERR %d: TCA9539: Failed to select PWDN signal source\n",
|
||||||
__func__, err);
|
__func__, err);
|
||||||
@@ -1722,7 +1645,7 @@ static int cdi_mgr_probe(struct platform_device *pdev)
|
|||||||
cdi_mgr->cim_frsync[0],
|
cdi_mgr->cim_frsync[0],
|
||||||
cdi_mgr->cim_frsync[1],
|
cdi_mgr->cim_frsync[1],
|
||||||
cdi_mgr->cim_frsync[2]);
|
cdi_mgr->cim_frsync[2]);
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x2,
|
if (tca9539_wr(cdi_mgr, 0x2,
|
||||||
(cdi_mgr->cim_frsync[2] << 4) |
|
(cdi_mgr->cim_frsync[2] << 4) |
|
||||||
(cdi_mgr->cim_frsync[1] << 2) |
|
(cdi_mgr->cim_frsync[1] << 2) |
|
||||||
(cdi_mgr->cim_frsync[0])) < 0) {
|
(cdi_mgr->cim_frsync[0])) < 0) {
|
||||||
@@ -1732,7 +1655,7 @@ static int cdi_mgr_probe(struct platform_device *pdev)
|
|||||||
goto err_probe;
|
goto err_probe;
|
||||||
}
|
}
|
||||||
/* Output low for AGGA/B/C/D_PWRDN */
|
/* Output low for AGGA/B/C/D_PWRDN */
|
||||||
if (tca9539_raw_wr(cdi_mgr, 0x3, 0x00) != 0) {
|
if (tca9539_wr(cdi_mgr, 0x3, 0x00) != 0) {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"%s: ERR %d: TCA9539: Failed to set the output level\n",
|
"%s: ERR %d: TCA9539: Failed to set the output level\n",
|
||||||
__func__, err);
|
__func__, err);
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
#define CDI_DEV_IOCTL_RW _IOW('o', 1, struct cdi_dev_package)
|
#define CDI_DEV_IOCTL_RW _IOW('o', 1, struct cdi_dev_package)
|
||||||
#define CDI_DEV_IOCTL_GET_PWR_INFO _IOW('o', 2, struct cdi_dev_pwr_ctrl_info)
|
#define CDI_DEV_IOCTL_GET_PWR_INFO _IOW('o', 2, struct cdi_dev_pwr_ctrl_info)
|
||||||
|
#define CDI_DEV_IOCTL_FRSYNC_MUX _IOW('o', 3, struct cdi_dev_fsync_mux)
|
||||||
|
|
||||||
#define DES_PWR_NVCCP 0U
|
#define DES_PWR_NVCCP 0U
|
||||||
#define DES_PWR_GPIO 1U
|
#define DES_PWR_GPIO 1U
|
||||||
@@ -27,6 +28,11 @@ struct __attribute__ ((__packed__)) cdi_dev_pwr_ctrl_info {
|
|||||||
__u8 cam_pwr_links[MAX_POWER_LINKS_PER_BLOCK];
|
__u8 cam_pwr_links[MAX_POWER_LINKS_PER_BLOCK];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct cdi_dev_fsync_mux {
|
||||||
|
__s8 mux_sel;
|
||||||
|
__s8 cam_grp;
|
||||||
|
};
|
||||||
|
|
||||||
struct __attribute__ ((__packed__)) cdi_dev_package {
|
struct __attribute__ ((__packed__)) cdi_dev_package {
|
||||||
__u16 offset;
|
__u16 offset;
|
||||||
__u16 offset_len;
|
__u16 offset_len;
|
||||||
|
|||||||
Reference in New Issue
Block a user