mirror of
git://nv-tegra.nvidia.com/linux-nv-oot.git
synced 2025-12-24 10:11:26 +03:00
Add ar0234 camera sensor driver code, max96712 GMSL serializer code, mode tables and makefile changes. These drivers are copied from K5.10 camera driver repo. Changes include svcacv warning fix and eeprom read status is ignored due to bug 4064490. Bug 3583587 Bug 4064490 Change-Id: I7ea0ecf959caccafd283c8db5fb7c3be912cf8bb Signed-off-by: Ankur Pawar <ankurp@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nv-oot/+/2868422 Reviewed-by: Laxman Dewangan <ldewangan@nvidia.com> GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
275 lines
6.1 KiB
C
275 lines
6.1 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* max96712.c - max96712 IO Expander driver
|
|
*
|
|
* Copyright (c) 2016-2023, NVIDIA CORPORATION & AFFILIATES. All Rights Reserved.
|
|
*/
|
|
|
|
/* #define DEBUG */
|
|
|
|
#include <linux/seq_file.h>
|
|
#include <linux/debugfs.h>
|
|
#include <media/camera_common.h>
|
|
#include <linux/module.h>
|
|
|
|
|
|
struct max96712 {
|
|
struct i2c_client *i2c_client;
|
|
struct regmap *regmap;
|
|
const char *channel;
|
|
};
|
|
static struct max96712 *global_priv[4];
|
|
|
|
int max96712_write_reg_Dser(int slaveAddr, int channel, u16 addr, u8 val);
|
|
int max96712_read_reg_Dser(int slaveAddr, int channel, u16 addr, unsigned int *val);
|
|
|
|
int max96712_write_reg_Dser(int slaveAddr, int channel,
|
|
u16 addr, u8 val)
|
|
{
|
|
struct i2c_client *i2c_client = NULL;
|
|
int bak = 0;
|
|
int err;
|
|
/* unsigned int ival = 0; */
|
|
|
|
if (channel > 3 || channel < 0 || global_priv[channel] == NULL)
|
|
return -1;
|
|
i2c_client = global_priv[channel]->i2c_client;
|
|
bak = i2c_client->addr;
|
|
|
|
i2c_client->addr = slaveAddr / 2;
|
|
err = regmap_write(global_priv[channel]->regmap, addr, val);
|
|
|
|
i2c_client->addr = bak;
|
|
if (err) {
|
|
dev_err(&i2c_client->dev, "%s: addr = 0x%x, val = 0x%x\n",
|
|
__func__, addr, val);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
EXPORT_SYMBOL(max96712_write_reg_Dser);
|
|
|
|
|
|
int max96712_read_reg_Dser(int slaveAddr, int channel,
|
|
u16 addr, unsigned int *val)
|
|
{
|
|
struct i2c_client *i2c_client = NULL;
|
|
int bak = 0;
|
|
int err;
|
|
|
|
if (channel > 3 || channel < 0 || global_priv[channel] == NULL)
|
|
return -1;
|
|
|
|
i2c_client = global_priv[channel]->i2c_client;
|
|
bak = i2c_client->addr;
|
|
i2c_client->addr = slaveAddr / 2;
|
|
|
|
err = regmap_read(global_priv[channel]->regmap, addr, val);
|
|
i2c_client->addr = bak;
|
|
if (err) {
|
|
dev_err(&i2c_client->dev, "%s: addr = 0x%x, val = 0x%x\n",
|
|
__func__, addr, *val);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
EXPORT_SYMBOL(max96712_read_reg_Dser);
|
|
|
|
static int max96712_read_reg(struct max96712 *priv,
|
|
u16 addr, unsigned int *val)
|
|
{
|
|
struct i2c_client *i2c_client = priv->i2c_client;
|
|
int err;
|
|
|
|
err = regmap_read(priv->regmap, addr, val);
|
|
if (err)
|
|
dev_err(&i2c_client->dev, "%s:i2c read failed, 0x%x = %x\n",
|
|
__func__, addr, *val);
|
|
|
|
return err;
|
|
}
|
|
|
|
|
|
static int max96712_stats_show(struct seq_file *s, void *data)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static int max96712_debugfs_open(struct inode *inode, struct file *file)
|
|
{
|
|
return single_open(file, max96712_stats_show, inode->i_private);
|
|
}
|
|
|
|
static ssize_t max96712_debugfs_write(struct file *s,
|
|
const char __user *user_buf,
|
|
size_t count, loff_t *ppos)
|
|
{
|
|
struct max96712 *priv =
|
|
((struct seq_file *)s->private_data)->private;
|
|
struct i2c_client *i2c_client = priv->i2c_client;
|
|
|
|
char buf[255];
|
|
int buf_size;
|
|
int val = 0;
|
|
|
|
if (!user_buf || count <= 1)
|
|
return -EFAULT;
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
buf_size = min(count, sizeof(buf) - 1);
|
|
if (copy_from_user(buf, user_buf, buf_size))
|
|
return -EFAULT;
|
|
|
|
if (buf[0] == 'd') {
|
|
dev_info(&i2c_client->dev, "%s, set daymode\n", __func__);
|
|
max96712_read_reg(priv, 0x0010, &val);
|
|
return count;
|
|
}
|
|
|
|
if (buf[0] == 'n') {
|
|
dev_info(&i2c_client->dev, "%s, set nightmode\n", __func__);
|
|
return count;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
static const struct file_operations max96712_debugfs_fops = {
|
|
.open = max96712_debugfs_open,
|
|
.read = seq_read,
|
|
.write = max96712_debugfs_write,
|
|
.llseek = seq_lseek,
|
|
.release = single_release,
|
|
};
|
|
|
|
static int max96712_debugfs_init(const char *dir_name,
|
|
struct dentry **d_entry,
|
|
struct dentry **f_entry,
|
|
struct max96712 *priv)
|
|
{
|
|
struct dentry *dp, *fp;
|
|
char dev_name[20];
|
|
struct i2c_client *i2c_client = priv->i2c_client;
|
|
struct device_node *np = i2c_client->dev.of_node;
|
|
int err = 0;
|
|
int index = 0;
|
|
|
|
if (np) {
|
|
err = of_property_read_string(np, "channel", &priv->channel);
|
|
if (err)
|
|
dev_err(&i2c_client->dev, "channel not found\n");
|
|
|
|
err = snprintf(dev_name, sizeof(dev_name), "max96712_%s", priv->channel);
|
|
if (err < 0)
|
|
return -EINVAL;
|
|
}
|
|
index = priv->channel[0] - 'a';
|
|
if (index < 0)
|
|
return -EINVAL;
|
|
global_priv[index] = priv;
|
|
|
|
dev_dbg(&i2c_client->dev, "%s: index %d\n", __func__, index);
|
|
|
|
dp = debugfs_create_dir(dev_name, NULL);
|
|
if (dp == NULL) {
|
|
dev_err(&i2c_client->dev, "%s: debugfs create dir failed\n",
|
|
__func__);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
fp = debugfs_create_file("max96712", 0644, dp, priv,
|
|
&max96712_debugfs_fops);
|
|
if (!fp) {
|
|
dev_err(&i2c_client->dev, "%s: debugfs create file failed\n",
|
|
__func__);
|
|
debugfs_remove_recursive(dp);
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (d_entry)
|
|
*d_entry = dp;
|
|
if (f_entry)
|
|
*f_entry = fp;
|
|
return 0;
|
|
}
|
|
|
|
static struct regmap_config max96712_regmap_config = {
|
|
.reg_bits = 16,
|
|
.val_bits = 8,
|
|
.cache_type = REGCACHE_RBTREE,
|
|
};
|
|
|
|
static int max96712_probe(struct i2c_client *client,
|
|
const struct i2c_device_id *id)
|
|
{
|
|
struct max96712 *priv;
|
|
int err = 0;
|
|
|
|
dev_info(&client->dev, "%s: enter\n", __func__);
|
|
|
|
priv = devm_kzalloc(&client->dev, sizeof(*priv), GFP_KERNEL);
|
|
priv->i2c_client = client;
|
|
priv->regmap = devm_regmap_init_i2c(priv->i2c_client,
|
|
&max96712_regmap_config);
|
|
if (IS_ERR(priv->regmap)) {
|
|
dev_err(&client->dev,
|
|
"regmap init failed: %ld\n", PTR_ERR(priv->regmap));
|
|
return -ENODEV;
|
|
}
|
|
|
|
err = max96712_debugfs_init(NULL, NULL, NULL, priv);
|
|
if (err)
|
|
return err;
|
|
|
|
/*set daymode by fault*/
|
|
dev_info(&client->dev, "%s: success\n", __func__);
|
|
|
|
return err;
|
|
}
|
|
|
|
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
|
static int max96712_remove(struct i2c_client *client)
|
|
#else
|
|
static void max96712_remove(struct i2c_client *client)
|
|
#endif
|
|
{
|
|
|
|
if (client != NULL) {
|
|
i2c_unregister_device(client);
|
|
client = NULL;
|
|
}
|
|
#if (KERNEL_VERSION(6, 1, 0) > LINUX_VERSION_CODE)
|
|
return 0;
|
|
#endif
|
|
}
|
|
|
|
static const struct i2c_device_id max96712_id[] = {
|
|
{ "max96712", 0 },
|
|
{ },
|
|
};
|
|
|
|
static const struct of_device_id max96712_of_match[] = {
|
|
{ .compatible = "nvidia,max96712", },
|
|
{ },
|
|
};
|
|
|
|
MODULE_DEVICE_TABLE(i2c, max96712_id);
|
|
|
|
static struct i2c_driver max96712_i2c_driver = {
|
|
.driver = {
|
|
.name = "max96712",
|
|
.owner = THIS_MODULE,
|
|
},
|
|
.probe = max96712_probe,
|
|
.remove = max96712_remove,
|
|
.id_table = max96712_id,
|
|
};
|
|
|
|
module_i2c_driver(max96712_i2c_driver);
|
|
|
|
MODULE_DESCRIPTION("IO Expander driver max96712");
|
|
MODULE_AUTHOR("NVIDIA Corporation");
|
|
MODULE_LICENSE("GPL v2");
|