kernel_samsung_a53x/drivers/media/platform/exynos/camera/is-dt.c

1668 lines
45 KiB
C
Raw Normal View History

2024-06-15 16:02:09 -03:00
/*
* Samsung Exynos5 SoC series FIMC-IS driver
*
* exynos5 fimc-is core functions
*
* Copyright (c) 2011 Samsung Electronics Co., Ltd
*
* 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.
*/
#if IS_ENABLED(CONFIG_OF)
#include <linux/sched.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <exynos-is.h>
#include "is-config.h"
#include "is-dt.h"
#include "is-core.h"
#include "is-dvfs.h"
#include "is-interface-sensor.h"
#include "is-device-camif-dma.h"
static int get_pin_lookup_state(struct pinctrl *pinctrl,
struct exynos_sensor_pin (*pin_ctrls)[GPIO_SCENARIO_MAX][GPIO_CTRL_MAX])
{
int ret = 0;
u32 i, j, k;
char pin_name[30];
struct pinctrl_state *s;
for (i = 0; i < SENSOR_SCENARIO_MAX; ++i) {
for (j = 0; j < GPIO_SCENARIO_MAX; ++j) {
for (k = 0; k < GPIO_CTRL_MAX; ++k) {
if (pin_ctrls[i][j][k].act == PIN_FUNCTION) {
snprintf(pin_name, sizeof(pin_name), "%s%d",
pin_ctrls[i][j][k].name,
pin_ctrls[i][j][k].value);
s = pinctrl_lookup_state(pinctrl, pin_name);
if (IS_ERR_OR_NULL(s)) {
err("pinctrl_lookup_state(%s) is failed", pin_name);
ret = -EINVAL;
goto p_err;
}
pin_ctrls[i][j][k].pin = (ulong)s;
}
}
}
}
p_err:
return ret;
}
static int parse_gate_info(struct exynos_platform_is *pdata, struct device_node *np)
{
int ret = 0;
struct device_node *group_np = NULL;
struct device_node *gate_info_np;
struct property *prop;
struct property *prop2;
const __be32 *p;
const char *s;
u32 i = 0, u = 0;
struct exynos_is_clk_gate_info *gate_info;
/* get subip of is info */
gate_info = kzalloc(sizeof(struct exynos_is_clk_gate_info), GFP_KERNEL);
if (!gate_info) {
printk(KERN_ERR "%s: no memory for is gate_info\n", __func__);
return -EINVAL;
}
s = NULL;
/* get gate register info */
prop2 = of_find_property(np, "clk_gate_strs", NULL);
of_property_for_each_u32(np, "clk_gate_enums", prop, p, u) {
printk(KERN_INFO "int value: %d\n", u);
s = of_prop_next_string(prop2, s);
if (s != NULL) {
printk(KERN_INFO "String value: %d-%s\n", u, s);
gate_info->gate_str[u] = s;
}
}
/* gate info */
gate_info_np = of_get_child_by_name(np, "clk_gate_ctrl");
if (!gate_info_np) {
ret = -ENOENT;
goto p_err;
}
i = 0;
while ((group_np = of_get_next_child(gate_info_np, group_np))) {
struct exynos_is_clk_gate_group *group =
&gate_info->groups[i];
of_property_for_each_u32(group_np, "mask_clk_on_org", prop, p, u) {
printk(KERN_INFO "(%d) int1 value: %d\n", i, u);
group->mask_clk_on_org |= (1 << u);
}
of_property_for_each_u32(group_np, "mask_clk_off_self_org", prop, p, u) {
printk(KERN_INFO "(%d) int2 value: %d\n", i, u);
group->mask_clk_off_self_org |= (1 << u);
}
of_property_for_each_u32(group_np, "mask_clk_off_depend", prop, p, u) {
printk(KERN_INFO "(%d) int3 value: %d\n", i, u);
group->mask_clk_off_depend |= (1 << u);
}
of_property_for_each_u32(group_np, "mask_cond_for_depend", prop, p, u) {
printk(KERN_INFO "(%d) int4 value: %d\n", i, u);
group->mask_cond_for_depend |= (1 << u);
}
i++;
printk(KERN_INFO "(%d) [0x%x , 0x%x, 0x%x, 0x%x\n", i,
group->mask_clk_on_org,
group->mask_clk_off_self_org,
group->mask_clk_off_depend,
group->mask_cond_for_depend
);
}
pdata->gate_info = gate_info;
return 0;
p_err:
kfree(gate_info);
return ret;
}
#if IS_ENABLED(CONFIG_PM_DEVFREQ)
static int parse_dvfs_data(struct exynos_platform_is *pdata, struct device_node *np)
{
int i, cnt;
u32 temp;
char *pprop;
const char *name;
char qos_name_l[IS_DVFS_END][IS_STR_LEN];
u32 dvfs_t;
for (dvfs_t = 0; dvfs_t < IS_DVFS_END; dvfs_t++) {
if (!pdata->qos_name[dvfs_t])
continue;
cnt = 0;
name = pdata->qos_name[dvfs_t];
while (name[cnt] != '\0' && cnt < IS_STR_LEN - 1) {
qos_name_l[dvfs_t][cnt] = tolower(name[cnt]);
cnt++;
}
qos_name_l[dvfs_t][cnt] = '\0';
}
pprop = __getname();
if (unlikely(!pprop))
return -ENOMEM;
for (i = 0; i < IS_SN_END; i++) {
for (dvfs_t = 0; dvfs_t < IS_DVFS_END; dvfs_t++) {
if (!pdata->qos_name[dvfs_t])
continue;
snprintf(pprop, PATH_MAX, "%s%s",
is_dvfs_dt_arr[i].parse_scenario_nm, qos_name_l[dvfs_t]);
DT_READ_U32_DEFAULT(np, pprop,
pdata->dvfs_data[is_dvfs_dt_arr[i].scenario_id][dvfs_t],
IS_DVFS_LV_END);
}
snprintf(pprop, PATH_MAX, "%s%s", is_dvfs_dt_arr[i].parse_scenario_nm, "hpg");
DT_READ_U32_DEFAULT(np, pprop,
pdata->dvfs_data[is_dvfs_dt_arr[i].scenario_id][IS_DVFS_HPG], 1);
snprintf(pprop, PATH_MAX, "%s%s", is_dvfs_dt_arr[i].parse_scenario_nm, "cpu");
DT_READ_STR(np, pprop, pdata->dvfs_cpu[is_dvfs_dt_arr[i].scenario_id]);
}
__putname(pprop);
#ifdef DBG_DUMP_DVFS_DT
for (i = 0; i < IS_SN_END; i++) {
probe_info("---- %s ----\n", is_dvfs_dt_arr[i].parse_scenario_nm);
for (dvfs_t = 0; dvfs_t < IS_DVFS_END; dvfs_t++) {
if (pdata->qos_name[dvfs_t])
probe_info("[%d][%s] = %d\n", i,
pdata->qos_name[dvfs_t],
pdata->dvfs_data[i][dvfs_t]);
}
probe_info("[%d][HPG] = %d\n", i, pdata->dvfs_data[i][IS_DVFS_HPG]);
probe_info("[%d][CPU] = %s\n", i, pdata->dvfs_cpu[i]);
}
#endif
return 0;
}
#else
static int parse_dvfs_data(struct exynos_platform_is *pdata, struct device_node *np)
{
return 0;
}
#endif
static int parse_qos_table(struct exynos_platform_is *pdata, struct device_node *np)
{
u32 dvfs_typ = 0;
int elems, lv;
struct device_node *next;
for_each_child_of_node(np, next) {
if (of_find_property(next, "typ", NULL)) {
of_property_read_u32(next, "typ", &dvfs_typ);
} else {
probe_warn("dvfs_typ read is fail");
return -EINVAL;
}
elems = of_property_count_u32_elems(next, "lev");
if (elems >= IS_DVFS_LV_END) {
probe_warn("too many elements");
continue;
}
pdata->qos_otf[dvfs_typ] = of_property_read_bool(next, "otf");
pdata->qos_name[dvfs_typ] = next->name;
for (lv = 0; lv < elems; lv++) {
of_property_read_u32_index(next, "lev", lv,
&pdata->qos_tb[dvfs_typ][lv][IS_DVFS_VAL_LEV]);
of_property_read_u32_index(next, "frq", lv,
&pdata->qos_tb[dvfs_typ][lv][IS_DVFS_VAL_FRQ]);
of_property_read_u32_index(next, "qos", lv,
&pdata->qos_tb[dvfs_typ][lv][IS_DVFS_VAL_QOS]);
}
}
return 0;
}
static int parse_dvfs_table(struct is_dvfs_ctrl *dvfs,
struct exynos_platform_is *pdata, struct device_node *np)
{
int ret = 0;
int table_cnt = 0;
struct device_node *table_np = NULL;
const char *dvfs_table_desc;
while ((table_np = of_get_next_child(np, table_np))) {
ret = of_property_read_string(table_np, "desc", &dvfs_table_desc);
if (ret)
dvfs_table_desc = "NOT defined";
probe_info("dvfs table[%d] is %s", table_cnt, dvfs_table_desc);
parse_dvfs_data(pdata, table_np);
table_cnt++;
}
return ret;
}
static int bts_parse_data(struct device_node *np, struct is_bts_scen **data, int *num_bts_scen)
{
int i;
int ret = 0;
int num_scen;
struct is_bts_scen *bts_scen;
if (of_have_populated_dt()) {
num_scen = (unsigned int)of_property_count_strings(np, "list-scen-bts");
if (num_scen <= 0) {
probe_warn("There should be at least one scenario\n");
goto err_of_property;
}
bts_scen = kcalloc(num_scen, sizeof(struct is_bts_scen), GFP_KERNEL);
if (bts_scen == NULL) {
ret = -ENOMEM;
probe_err("no memory for bts_scen");
goto err_alloc;
}
for (i = 0; i < num_scen; i++) {
bts_scen[i].index = i;
ret = of_property_read_string_index(np, "list-scen-bts", i, &(bts_scen[i].name));
if (ret < 0) {
probe_err("Unable to get name of bts scenarios\n");
goto err_read_string;
}
}
*data = bts_scen;
*num_bts_scen = num_scen;
} else {
probe_warn("Invalid device tree node!\n");
}
return 0;
err_read_string:
kfree(bts_scen);
err_alloc:
err_of_property:
return ret;
}
static int parse_lic_offset_data(struct is_hardware *is_hw, struct device_node *dnode)
{
int ret = 0;
char *str_lic_ip;
int elems;
u32 offsets = LIC_CHAIN_OFFSET_NUM / 2 - 1;
u32 set_idx = offsets + 1;
int i, index_a, index_b;
char *str_a, *str_b;
str_lic_ip = __getname();
if (unlikely(!str_lic_ip)) {
err("[@] out of memory for str_lic_ip!");
ret = -ENOMEM;
goto err_alloc_str_lic_ip;
}
snprintf(str_lic_ip, PATH_MAX, "3AA");
if (of_property_read_bool(dnode, str_lic_ip)) {
elems = of_property_count_u32_elems(dnode, str_lic_ip);
if (elems != LIC_CHAIN_OFFSET_NUM) {
err("wrong LIC_CHAIN_OFFSET_NUM(%d!=%d)", elems, LIC_CHAIN_OFFSET_NUM);
ret = -EINVAL;
goto err_get_elems;
}
of_property_read_u32_array(dnode, str_lic_ip,
&is_hw->lic_offset_def[0], elems);
} else {
err("[@] Can't fine %s node", str_lic_ip);
}
probe_info("[@] Parse_lic_offset_data\n");
index_a = COREX_SETA * set_idx; /* setA */
index_b = COREX_SETB * set_idx; /* setB */
str_a = __getname();
if (unlikely(!str_a)) {
err("[@] out of memory for str_a!");
ret = -ENOMEM;
goto err_alloc_str_a;
}
str_b = __getname();
if (unlikely(!str_b)) {
err("[@] out of memory for str_b!");
ret = -ENOMEM;
goto err_alloc_str_b;
}
snprintf(str_a, PATH_MAX, "%d", is_hw->lic_offset_def[index_a + 0]);
snprintf(str_b, PATH_MAX, "%d", is_hw->lic_offset_def[index_b + 0]);
for (i = 1; i < offsets; i++) {
snprintf(str_a, PATH_MAX, "%s, %d", str_a, is_hw->lic_offset_def[index_a + i]);
snprintf(str_b, PATH_MAX, "%s, %d", str_b, is_hw->lic_offset_def[index_b + i]);
}
probe_info("[@] 3AA lic_offset_def: setA<%s>(%d), setB<%s>(%d)",
str_a, is_hw->lic_offset_def[index_a + offsets],
str_b, is_hw->lic_offset_def[index_b + offsets]);
__putname(str_b);
err_alloc_str_b:
__putname(str_a);
err_alloc_str_a:
err_get_elems:
__putname(str_lic_ip);
err_alloc_str_lic_ip:
return ret;
}
static int parse_phy_ldos(struct device *dev, struct regulator ***ldos, int *num)
{
struct device_node *np = dev->of_node;
int i, ret;
const char *name;
*num = of_property_count_strings(np, "phy_ldos");
if (IS_ERR_VALUE((unsigned long)*num)) {
probe_info("no power controls for CSI PHYs\n");
return 0;
}
*ldos = kcalloc(*num, sizeof(struct regulator *), GFP_KERNEL);
if (!(*ldos)) {
probe_err("failed to allocate memory for PHY regulators\n");
*num = 0;
return -ENOMEM;
}
for (i = 0; i < *num; i++) {
ret = of_property_read_string_index(np, "phy_ldos", i, &name);
if (ret) {
probe_err("failed get the name of PHY ldo%d: %d\n", i, ret);
goto err_read_name;
}
(*ldos)[i] = regulator_get(dev, name);
if (IS_ERR((*ldos)[i])) {
probe_err("failed get regulator - %s: %d\n", name, (*ldos)[i]);
ret = PTR_ERR((*ldos)[i]);
goto err_get_regulator;
}
probe_info("LDO[%d] for CSI PHYs: %s was probed\n", i, name);
}
return 0;
err_get_regulator:
err_read_name:
while (i-- > 0)
regulator_put((*ldos)[i]);
kfree(*ldos);
*num = 0;
return ret;
}
static int parse_itmon_port_name(struct device_node *np, struct is_resourcemgr *resourcemgr)
{
int ret;
int num;
const char **name;
num = of_property_count_strings(np, "itmon_port_name");
if (num <= 0) {
probe_warn("There should be at least one port");
ret = -ENODEV;
goto err_of_property;
}
name = kcalloc(num, sizeof(char *), GFP_KERNEL);
if (!name) {
ret = -ENOMEM;
probe_err("Out of memory for itmon_port_name");
goto err_alloc;
}
ret = of_property_read_string_array(np, "itmon_port_name", name, num);
if (ret < 0) {
probe_err("Unable to get itmon_port_name\n");
goto err_read_string;
}
resourcemgr->itmon_port_num = num;
resourcemgr->itmon_port_name = name;
return 0;
err_read_string:
kfree(*name);
err_alloc:
err_of_property:
return ret;
}
static int parse_cpu_data(struct device_node *np, struct exynos_platform_is *pdata)
{
struct device_node *cluster_np = NULL;
cluster_np = of_get_child_by_name(np, "cpus");
if (cluster_np) {
of_property_read_u32(cluster_np, "cluster0", &pdata->cpu_cluster[0]);
of_property_read_u32(cluster_np, "cluster1", &pdata->cpu_cluster[1]);
of_property_read_u32(cluster_np, "cluster2", &pdata->cpu_cluster[2]);
} else {
pdata->cpu_cluster[0] = 0;
pdata->cpu_cluster[1] = 4;
pdata->cpu_cluster[2] = 7;
}
probe_info("cpu_cluster(%d, %d, %d)",
pdata->cpu_cluster[0], pdata->cpu_cluster[1], pdata->cpu_cluster[2]);
return 0;
}
int is_chain_dev_parse_dt(struct platform_device *pdev)
{
int ret = 0;
struct is_core *core;
struct is_dvfs_ctrl *dvfs;
struct is_bts_scen **bts_scen;
struct exynos_platform_is *pdata;
struct device *dev;
struct device_node *qos_np = NULL;
struct device_node *dvfs_np = NULL;
struct device_node *vender_np = NULL;
struct device_node *lic_offset_np = NULL;
struct device_node *buffer_np = NULL;
struct device_node *np;
u32 mem_info[2];
FIMC_BUG(!pdev);
dev = &pdev->dev;
np = dev->of_node;
core = dev_get_drvdata(&pdev->dev);
if (!core) {
probe_err("core is NULL");
return -ENOMEM;
}
pdata = kzalloc(sizeof(struct exynos_platform_is), GFP_KERNEL);
if (!pdata) {
probe_err("no memory for platform data");
return -ENOMEM;
}
dvfs = &core->resourcemgr.dvfs_ctrl;
bts_scen = &core->resourcemgr.bts_scen;
is_get_clk_ops(pdata);
parse_itmon_port_name(np, &core->resourcemgr);
parse_cpu_data(np, pdata);
of_property_read_u32(np, "num_of_3aa", &pdata->num_of_ip.taa);
of_property_read_u32(np, "num_of_lme", &pdata->num_of_ip.lme);
of_property_read_u32(np, "num_of_orbmch", &pdata->num_of_ip.orbmch);
of_property_read_u32(np, "num_of_isp", &pdata->num_of_ip.isp);
of_property_read_u32(np, "num_of_byrp", &pdata->num_of_ip.byrp);
of_property_read_u32(np, "num_of_rgbp", &pdata->num_of_ip.rgbp);
of_property_read_u32(np, "num_of_mcsc", &pdata->num_of_ip.mcsc);
of_property_read_u32(np, "num_of_vra", &pdata->num_of_ip.vra);
of_property_read_u32(np, "num_of_ypp", &pdata->num_of_ip.ypp);
of_property_read_u32(np, "num_of_mcfp", &pdata->num_of_ip.mcfp);
if (parse_gate_info(pdata, np) < 0)
probe_info("can't parse clock gate info node");
ret = of_property_read_u32(np, "chain_config", &core->chain_config);
if (ret)
probe_warn("chain configuration read is fail(%d)", ret);
probe_info("FIMC-IS chain configuration: %d\n", core->chain_config);
ret = of_property_read_u32_array(np, "secure_mem_info", mem_info, 2);
if (ret) {
core->secure_mem_info[0] = 0;
core->secure_mem_info[1] = 0;
} else {
core->secure_mem_info[0] = mem_info[0];
core->secure_mem_info[1] = mem_info[1];
}
probe_info("ret(%d) secure_mem_info(%#08lx, %#08lx)", ret,
core->secure_mem_info[0], core->secure_mem_info[1]);
ret = of_property_read_u32_array(np, "non_secure_mem_info", mem_info, 2);
if (ret) {
core->non_secure_mem_info[0] = 0;
core->non_secure_mem_info[1] = 0;
} else {
core->non_secure_mem_info[0] = mem_info[0];
core->non_secure_mem_info[1] = mem_info[1];
}
probe_info("ret(%d) non_secure_mem_info(%#08lx, %#08lx)", ret,
core->non_secure_mem_info[0], core->non_secure_mem_info[1]);
ret = of_property_read_u32_array(np, "memlog_size", pdata->is_memlog_size, 2);
if (ret) {
pdata->is_memlog_size[0] = IS_MEMLOG_PRINTF_DRV_SIZE;
pdata->is_memlog_size[1] = IS_MEMLOG_PRINTF_DDK_SIZE;
}
probe_info("ret(%d) is_memlog_size(0x%#08lx, 0x%#08lx)", ret,
pdata->is_memlog_size[0], pdata->is_memlog_size[1]);
vender_np = of_get_child_by_name(np, "vender");
if (vender_np) {
ret = is_vender_dt(vender_np);
if (ret)
probe_err("is_vender_dt is fail(%d)", ret);
}
pdata->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(pdata->pinctrl)) {
probe_err("devm_pinctrl_get is fail");
goto p_err;
}
qos_np = of_get_child_by_name(np, "is_qos");
if (qos_np) {
ret = parse_qos_table(pdata, qos_np);
if (ret)
probe_err("parse_qos_table is fail(%d)", ret);
}
dvfs_np = of_get_child_by_name(np, "is_dvfs");
if (dvfs_np) {
ret = parse_dvfs_table(dvfs, pdata, dvfs_np);
if (ret)
probe_err("parse_dvfs_table is fail(%d)", ret);
}
bts_parse_data(np, bts_scen, &core->resourcemgr.num_bts_scen);
lic_offset_np = of_get_child_by_name(np, "lic_offsets");
if (lic_offset_np) {
ret = parse_lic_offset_data(&core->hardware, lic_offset_np);
if (ret)
probe_err("parse_lic_offset_data is fail(%d)", ret);
}
buffer_np = of_get_child_by_name(np, "buffer_info");
if (buffer_np) {
of_property_read_u32(buffer_np, "ypp_buf_max_width",
&core->hardware.ypp_internal_buf_max_width);
}
ret = parse_phy_ldos(dev, &core->resourcemgr.phy_ldos,
&core->resourcemgr.num_phy_ldos);
if (ret)
goto p_err;
dev->platform_data = pdata;
return 0;
p_err:
kfree(pdata);
return ret;
}
int is_sensor_dev_parse_dt(struct platform_device *pdev)
{
int ret;
struct exynos_platform_is_sensor *pdata;
struct device_node *dnode;
struct device *dev;
FIMC_BUG(!pdev);
FIMC_BUG(!pdev->dev.of_node);
dev = &pdev->dev;
dnode = dev->of_node;
pdata = kzalloc(sizeof(struct exynos_platform_is_sensor), GFP_KERNEL);
if (!pdata) {
err("%s: no memory for platform data", __func__);
return -ENOMEM;
}
is_sensor_get_clk_ops(pdata);
ret = of_property_read_u32(dnode, "id", &pdata->id);
if (ret) {
err("id read is fail(%d)", ret);
goto err_read_id;
}
ret = of_property_read_u32(dnode, "scenario", &pdata->scenario);
if (ret) {
err("scenario read is fail(%d)", ret);
goto err_read_scenario;
}
ret = of_property_read_u32(dnode, "csi_ch", &pdata->csi_ch);
if (ret) {
err("csi_ch read is fail(%d)", ret);
goto err_read_csi_ch;
}
ret = of_property_read_u32(dnode, "wdma_ch_hint", &pdata->wdma_ch_hint);
if (ret) {
probe_info("skip wdma_ch_hint data read (%d)", ret);
pdata->wdma_ch_hint = INIT_WDMA_CH_HINT;
}
ret = of_property_read_u32(dnode, "csi_mux", &pdata->csi_mux);
if (ret) {
probe_info("skip phy-csi mux data read (%d)", ret);
}
ret = of_property_read_u32(dnode, "multi_ch", &pdata->multi_ch);
if (ret) {
probe_info("skip multi_ch bool data read (%d)", ret);
}
ret = of_property_read_u32(dnode, "use_cphy", &pdata->use_cphy);
if (ret)
probe_info("use_cphy read is fail(%d)", ret);
ret = of_property_read_u32(dnode, "scramble", &pdata->scramble);
if (ret)
probe_info("scramble read is fail(%d)", ret);
ret = of_property_read_u32(dnode, "i2c_dummy_enable", &pdata->i2c_dummy_enable);
if (ret)
probe_info("i2c_dummy_enable is false(%d)", ret);
pdev->id = pdata->id;
dev->platform_data = pdata;
return 0;
err_read_csi_ch:
err_read_scenario:
err_read_id:
kfree(pdata);
return ret;
}
static int is_board_cfg_parse_dt(struct device_node *dnode,
struct exynos_platform_is_module *pdata)
{
int ret;
ret = of_property_read_u32(dnode, "id", &pdata->id);
if (ret) {
probe_err("id read is fail(%d)", ret);
return ret;
}
ret = of_property_read_u32(dnode, "mclk_ch", &pdata->mclk_ch);
if (ret) {
probe_err("mclk_ch read is fail(%d)", ret);
return ret;
}
if (of_property_read_u32(dnode, "mclk_freq", &pdata->mclk_freq_khz)) {
pdata->mclk_freq_khz = 26000;
probe_info("mclk_freq set as default 26Mhz\n");
} else {
probe_info("mclk_freq set as %d.%dMhz\n", pdata->mclk_freq_khz / 1000,
pdata->mclk_freq_khz - (pdata->mclk_freq_khz / 1000) * 1000);
}
if (of_property_read_u32(dnode, "sensor_i2c_ch", &pdata->sensor_i2c_ch))
probe_info("i2c_ch dt parsing skipped\n");
if (of_property_read_u32(dnode, "sensor_i2c_addr", &pdata->sensor_i2c_addr))
probe_info("i2c_addr dt parsing skipped\n");
ret = of_property_read_u32(dnode, "position", &pdata->position);
if (ret) {
probe_err("position read is fail(%d)", ret);
return ret;
}
return ret;
}
static void is_module_cfg_parse_dt(struct device_node *dnode,
struct exynos_platform_is_module *pdata)
{
if (of_property_read_u32(dnode, "sensor_id", &pdata->sensor_id))
probe_warn("sensor_id read is skipped");
if (of_property_read_u32(dnode, "active_width", &pdata->active_width))
probe_warn("active_width read is skipped");
if (of_property_read_u32(dnode, "active_height", &pdata->active_height))
probe_warn("active_height read is skipped");
if (of_property_read_u32(dnode, "margin_left", &pdata->margin_left))
probe_warn("margin_left read is skipped");
if (of_property_read_u32(dnode, "margin_right", &pdata->margin_right))
probe_warn("margin_right read is skipped");
if (of_property_read_u32(dnode, "margin_top", &pdata->margin_top))
probe_warn("margin_top read is skipped");
if (of_property_read_u32(dnode, "margin_bottom", &pdata->margin_bottom))
probe_warn("margin_bottom read is skipped");
if (of_property_read_u32(dnode, "max_framerate", &pdata->max_framerate))
probe_warn("max_framerate read is skipped");
if (of_property_read_u32(dnode, "bitwidth", &pdata->bitwidth))
probe_warn("bitwidth read is skipped");
if (of_property_read_u32(dnode, "use_retention_mode", &pdata->use_retention_mode))
probe_warn("use_retention_mode read is skipped");
if (of_property_read_u32(dnode, "use_binning_ratio_table", &pdata->use_binning_ratio_table))
probe_warn("use_binning_ratio_table read is skipped");
if (of_property_read_string(dnode, "sensor_maker", (const char **)&pdata->sensor_maker))
probe_warn("sensor_maker read is skipped");
if (of_property_read_string(dnode, "sensor_name", (const char **)&pdata->sensor_name))
probe_warn("sensor_name read is skipped");
if (of_property_read_string(dnode, "setfile_name", (const char **)&pdata->setfile_name))
probe_warn("setfile_name read is skipped");
if (of_property_read_u32(dnode, "sensor_module_type", &pdata->sensor_module_type)) {
probe_warn("sensor_module_type read is skipped");
pdata->sensor_module_type = SENSOR_TYPE_RGB;
}
}
static void is_module_rom_parse_dt(struct device_node *dnode,
struct exynos_platform_is_module *pdata)
{
if (of_property_read_u32(dnode, "rom_id", &pdata->rom_id)) {
probe_info("rom_id dt parsing skipped\n");
pdata->rom_id = ROM_ID_NOTHING;
}
if (of_property_read_u32(dnode, "rom_type", &pdata->rom_type)) {
probe_info("rom_type dt parsing skipped\n");
pdata->rom_type = ROM_TYPE_NONE;
}
if (of_property_read_u32(dnode, "rom_cal_index", &pdata->rom_cal_index)) {
probe_info("rom_cal_index dt parsing skipped\n");
pdata->rom_cal_index = ROM_CAL_NOTHING;
}
if (of_property_read_u32(dnode, "rom_dualcal_id", &pdata->rom_dualcal_id)) {
probe_info("rom_dualcal_id dt parsing skipped\n");
pdata->rom_dualcal_id = ROM_ID_NOTHING;
}
if (of_property_read_u32(dnode, "rom_dualcal_index", &pdata->rom_dualcal_index)) {
probe_info("rom_dualcal_index dt parsing skipped\n");
pdata->rom_dualcal_index = ROM_DUALCAL_NOTHING;
}
}
static int parse_af_data(struct exynos_platform_is_module *pdata, struct device_node *dnode)
{
u32 temp;
char *pprop;
DT_READ_U32(dnode, "product_name", pdata->af_product_name);
DT_READ_U32(dnode, "i2c_addr", pdata->af_i2c_addr);
DT_READ_U32(dnode, "i2c_ch", pdata->af_i2c_ch);
return 0;
}
static int parse_flash_data(struct exynos_platform_is_module *pdata, struct device_node *dnode)
{
u32 temp;
char *pprop;
DT_READ_U32(dnode, "product_name", pdata->flash_product_name);
DT_READ_U32(dnode, "flash_first_gpio", pdata->flash_first_gpio);
DT_READ_U32(dnode, "flash_second_gpio", pdata->flash_second_gpio);
return 0;
}
static int parse_ois_data(struct exynos_platform_is_module *pdata, struct device_node *dnode)
{
u32 temp;
char *pprop;
DT_READ_U32(dnode, "product_name", pdata->ois_product_name);
DT_READ_U32(dnode, "i2c_addr", pdata->ois_i2c_addr);
DT_READ_U32(dnode, "i2c_ch", pdata->ois_i2c_ch);
return 0;
}
static int parse_mcu_data(struct exynos_platform_is_module *pdata, struct device_node *dnode)
{
u32 temp;
char *pprop;
DT_READ_U32(dnode, "product_name", pdata->mcu_product_name);
DT_READ_U32(dnode, "i2c_addr", pdata->mcu_i2c_addr);
DT_READ_U32(dnode, "i2c_ch", pdata->mcu_i2c_ch);
return 0;
}
static int parse_aperture_data(struct exynos_platform_is_module *pdata, struct device_node *dnode)
{
u32 temp;
char *pprop;
DT_READ_U32(dnode, "product_name", pdata->aperture_product_name);
DT_READ_U32(dnode, "i2c_addr", pdata->aperture_i2c_addr);
DT_READ_U32(dnode, "i2c_ch", pdata->aperture_i2c_ch);
return 0;
}
static int parse_eeprom_data(struct exynos_platform_is_module *pdata, struct device_node *dnode)
{
u32 temp;
char *pprop;
DT_READ_U32(dnode, "product_name", pdata->eeprom_product_name);
DT_READ_U32(dnode, "i2c_addr", pdata->eeprom_i2c_addr);
DT_READ_U32(dnode, "i2c_ch", pdata->eeprom_i2c_ch);
return 0;
}
static int parse_laser_af_data(struct exynos_platform_is_module *pdata, struct device_node *dnode)
{
u32 temp;
char *pprop;
DT_READ_U32(dnode, "product_name", pdata->laser_af_product_name);
return 0;
}
static void is_module_peris_parse_dt(struct device_node *dnode,
struct exynos_platform_is_module *pdata)
{
struct device_node *cis_np;
struct device_node *af_np;
struct device_node *flash_np;
struct device_node *ois_np;
struct device_node *mcu_np;
struct device_node *aperture_np;
struct device_node *eeprom_np;
struct device_node *laser_af_np;
u32 temp;
char *pprop;
cis_np = of_get_child_by_name(dnode, "cis");
if (cis_np) {
DT_READ_U32_DEFAULT(cis_np, "reg",
pdata->sensor_i2c_addr,
pdata->sensor_i2c_addr);
pdata->cis_np = cis_np;
}
af_np = of_get_child_by_name(dnode, "af");
if (!af_np) {
pdata->af_product_name = ACTUATOR_NAME_NOTHING;
} else {
parse_af_data(pdata, af_np);
DT_READ_U32_DEFAULT(af_np, "reg",
pdata->af_i2c_addr,
pdata->af_i2c_addr);
pdata->af_np = af_np;
}
flash_np = of_get_child_by_name(dnode, "flash");
if (!flash_np) {
pdata->flash_product_name = FLADRV_NAME_NOTHING;
} else {
parse_flash_data(pdata, flash_np);
}
ois_np = of_get_child_by_name(dnode, "ois");
if (!ois_np) {
pdata->ois_product_name = OIS_NAME_NOTHING;
} else {
parse_ois_data(pdata, ois_np);
DT_READ_U32_DEFAULT(ois_np, "reg",
pdata->ois_i2c_addr,
pdata->ois_i2c_addr);
pdata->ois_np = ois_np;
}
mcu_np = of_get_child_by_name(dnode, "mcu");
if (!mcu_np)
pdata->mcu_product_name = MCU_NAME_NOTHING;
else
parse_mcu_data(pdata, mcu_np);
aperture_np = of_get_child_by_name(dnode, "aperture");
if (!aperture_np)
pdata->aperture_product_name = APERTURE_NAME_NOTHING;
else
parse_aperture_data(pdata, aperture_np);
eeprom_np = of_find_node_by_name(dnode, "eeprom");
if (!eeprom_np) {
pdata->eeprom_product_name = EEPROM_NAME_NOTHING;
} else {
parse_eeprom_data(pdata, eeprom_np);
DT_READ_U32_DEFAULT(eeprom_np, "reg",
pdata->eeprom_i2c_addr,
pdata->eeprom_i2c_addr);
pdata->eeprom_np = eeprom_np;
}
laser_af_np = of_get_child_by_name(dnode, "laser_af");
if (!laser_af_np)
pdata->laser_af_product_name = LASER_AF_NAME_NOTHING;
else
parse_laser_af_data(pdata, laser_af_np);
}
static int is_cis_vc_extra_parse_dt(struct device_node *dnode,
struct exynos_platform_is_module *pdata)
{
struct device_node *vc_extra_np;
int idx_stat;
int idx_dt;
char *str_stat;
vc_extra_np = of_get_child_by_name(dnode, "vc_extra");
if (!vc_extra_np) {
probe_warn("sensor vc_extra are not declared to DT");
return 0;
}
str_stat = __getname();
if (!str_stat) {
err("out of memory for str_stat.");
return -ENOMEM;
}
for (idx_stat = 0; idx_stat < VC_BUF_DATA_TYPE_MAX; idx_stat++) {
idx_dt = 0;
snprintf(str_stat, PATH_MAX, "%s%d", "stat", idx_stat);
if (!of_find_property(vc_extra_np, str_stat, NULL)) {
pdata->vc_extra_info[idx_stat].stat_type = VC_STAT_TYPE_INVALID;
pdata->vc_extra_info[idx_stat].sensor_mode = VC_SENSOR_MODE_INVALID;
pdata->vc_extra_info[idx_stat].max_width = 0;
pdata->vc_extra_info[idx_stat].max_height = 0;
pdata->vc_extra_info[idx_stat].max_element = 0;
continue;
}
of_property_read_u32_index(vc_extra_np, str_stat, idx_dt++,
&pdata->vc_extra_info[idx_stat].stat_type);
of_property_read_u32_index(vc_extra_np, str_stat, idx_dt++,
&pdata->vc_extra_info[idx_stat].sensor_mode);
of_property_read_u32_index(vc_extra_np, str_stat, idx_dt++,
&pdata->vc_extra_info[idx_stat].max_width);
of_property_read_u32_index(vc_extra_np, str_stat, idx_dt++,
&pdata->vc_extra_info[idx_stat].max_height);
of_property_read_u32_index(vc_extra_np, str_stat, idx_dt++,
&pdata->vc_extra_info[idx_stat].max_element);
}
if (of_property_read_u32(vc_extra_np, "stat_vc", &pdata->stat_vc)) {
probe_warn("Use VC1 for PD stat out");
pdata->stat_vc = CSI_VIRTUAL_CH_1;
}
__putname(str_stat);
return 0;
}
static void is_cis_opt_parse_dt(struct device_node *dnode,
struct exynos_platform_is_module *pdata, struct is_sensor_cfg *cfg)
{
struct device_node *opt_np;
u32 idx_vc;
u32 dummy_idx;
u32 vc_num;
u32 elems;
opt_np = of_get_child_by_name(dnode, "option");
/* default value */
cfg->votf = 0;
cfg->wdma_ch_hint = INIT_WDMA_CH_HINT;
cfg->max_fps = cfg->framerate;
cfg->binning = min(BINNING(pdata->active_width, cfg->width),
BINNING(pdata->active_height, cfg->height));
cfg->vvalid_time = 0;
cfg->req_vvalid_time = 0;
cfg->special_mode = -1;
for (idx_vc = 0; idx_vc < CSI_VIRTUAL_CH_MAX; idx_vc++)
cfg->dummy_pixel[idx_vc] = 0;
cfg->fid_loc.valid = 0;
cfg->dvfs_lv_csis = IS_DVFS_LV_END;
if (opt_np) {
if (of_find_property(opt_np, "votf", NULL))
of_property_read_u32(opt_np, "votf", &cfg->votf);
if (of_find_property(opt_np, "wdma_ch_hint", NULL))
of_property_read_u32(opt_np, "wdma_ch_hint", &cfg->wdma_ch_hint);
if (of_find_property(opt_np, "max_fps", NULL))
of_property_read_u32(opt_np, "max_fps", &cfg->max_fps);
if (of_find_property(opt_np, "binning", NULL))
of_property_read_u32(opt_np, "binning", &cfg->binning);
if (of_find_property(opt_np, "vvalid_time", NULL))
of_property_read_u32(opt_np, "vvalid_time", &cfg->vvalid_time);
if (of_find_property(opt_np, "req_vvalid_time", NULL))
of_property_read_u32(opt_np, "req_vvalid_time", &cfg->req_vvalid_time);
if (of_find_property(opt_np, "special_mode", NULL))
of_property_read_u32(opt_np, "special_mode", &cfg->special_mode);
if (of_find_property(opt_np, "dummy_pixel", NULL)) {
elems = of_property_count_u32_elems(opt_np, "dummy_pixel");
if (elems % SENSOR_DUMMY_ELEMS) {
err("the length of dummy info. is not a multiple of SENSOR_DUMMY_ELEMS");
} else {
dummy_idx = 0;
while (elems > 0) {
of_property_read_u32_index(opt_np, "dummy_pixel",
dummy_idx++, &vc_num);
of_property_read_u32_index(opt_np, "dummy_pixel",
dummy_idx++, &cfg->dummy_pixel[vc_num]);
elems = elems - 2;
}
}
}
if (of_find_property(opt_np, "fid_loc", NULL)) {
of_property_read_u32_index(opt_np, "fid_loc", 0, &cfg->fid_loc.line);
of_property_read_u32_index(opt_np, "fid_loc", 1, &cfg->fid_loc.byte);
cfg->fid_loc.valid = 1;
}
if (of_find_property(opt_np, "dvfs_lv_csis", NULL))
of_property_read_u32(opt_np, "dvfs_lv_csis", &cfg->dvfs_lv_csis);
#ifdef USE_EX_MODE_EXTRA
if (opt_np && of_find_property(opt_np, "ex_mode_extra", NULL))
of_property_read_u32(opt_np, "ex_mode_extra", &cfg->ex_mode_extra);
else
cfg->ex_mode_extra = EX_EXTRA_NONE;
#else
cfg->ex_mode_extra = EX_EXTRA_NONE;
#endif
}
}
static int is_cis_modes_parse_dt(struct device_node *dnode,
struct exynos_platform_is_module *pdata)
{
struct device_node *modes_np;
struct device_node *next;
int idx_mode;
int idx_vc;
int idx_dt;
char *str_vc;
struct is_sensor_cfg *cfg;
u32 format;
int ret = 0;
modes_np = of_get_child_by_name(dnode, "modes");
if (!modes_np) {
probe_warn("sensor modes are not declared to DT");
return 0;
}
str_vc = __getname();
if (!str_vc) {
err("out of memory for str_vc.");
ret = -ENOMEM;
goto err_alloc_str_vc;
}
pdata->cfgs = of_get_child_count(modes_np);
pdata->cfg = kcalloc(pdata->cfgs, sizeof(struct is_sensor_cfg), GFP_KERNEL);
if (!pdata->cfg) {
err("out of memory for sensor modes.");
ret = -ENOMEM;
goto err_alloc_sensor_mode;
}
idx_mode = 0;
for_each_child_of_node(modes_np, next) {
idx_dt = 0;
cfg = &pdata->cfg[idx_mode];
idx_mode++;
of_property_read_u32_index(next, "common", idx_dt++, &cfg->width);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->height);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->framerate);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->settle);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->mode);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->lanes);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->mipi_speed);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->interleave_mode);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->lrte);
of_property_read_u32_index(next, "common", idx_dt++, &cfg->pd_mode);
of_property_read_u32_index(next, "common", idx_dt++, (u32 *)&cfg->ex_mode);
for (idx_vc = 0; idx_vc < CSI_VIRTUAL_CH_MAX; idx_vc++) {
idx_dt = 0;
snprintf(str_vc, PATH_MAX, "%s%d", "vc", idx_vc);
if (!of_find_property(next, str_vc, NULL))
break;
/* input format pasing */
of_property_read_u32_index(next, str_vc, idx_dt++, &cfg->input[idx_vc].map);
of_property_read_u32_index(next, str_vc, idx_dt++, &format);
cfg->input[idx_vc].hwformat = format & HW_FORMAT_MASK;
cfg->input[idx_vc].extformat = format & HW_EXT_FORMAT_MASK;
of_property_read_u32_index(next, str_vc, idx_dt++, &cfg->input[idx_vc].width);
of_property_read_u32_index(next, str_vc, idx_dt++, &cfg->input[idx_vc].height);
/* output format pasing */
of_property_read_u32_index(next, str_vc, idx_dt++, &format);
cfg->output[idx_vc].hwformat = format & HW_FORMAT_MASK;
cfg->output[idx_vc].extformat = format & HW_EXT_FORMAT_MASK;
of_property_read_u32_index(next, str_vc, idx_dt++, &cfg->output[idx_vc].type);
of_property_read_u32_index(next, str_vc, idx_dt++, &cfg->output[idx_vc].width);
of_property_read_u32_index(next, str_vc, idx_dt++, &cfg->output[idx_vc].height);
}
cfg->max_vc = idx_vc - 1;
is_cis_opt_parse_dt(next, pdata, cfg);
}
err_alloc_sensor_mode:
__putname(str_vc);
err_alloc_str_vc:
return ret;
}
static int parse_power_seq_data(struct exynos_platform_is_module *pdata, struct device_node *dnode)
{
int ret = 0;
u32 temp;
char *pprop;
struct device_node *sn_np, *seq_np;
struct is_core *core;
struct device_node **node_table;
struct device_node *temp_node;
int num;
long *node_num;
long temp_num;
int i, j;
int gpio_mclk;
core = is_get_is_core();
if (!core) {
probe_err("core is NULL");
return -EINVAL;
}
gpio_mclk = of_get_named_gpio(dnode, "gpio_mclk", 0);
if (gpio_is_valid(gpio_mclk)) {
if (gpio_request_one(gpio_mclk, GPIOF_OUT_INIT_LOW, "CAM_MCLK_OUTPUT_LOW")) {
probe_err("%s: failed to gpio request mclk\n", dnode->name);
return -ENODEV;
}
gpio_free(gpio_mclk);
} else {
probe_err("%s: failed to get mclk\n", dnode->name);
return -EINVAL;
}
for_each_child_of_node(dnode, sn_np) {
u32 sensor_scenario, gpio_scenario;
DT_READ_U32(sn_np, "sensor_scenario", sensor_scenario);
DT_READ_U32(sn_np, "gpio_scenario",gpio_scenario);
probe_info("power_seq[%s] : sensor_scenario=%d, gpio_scenario=%d\n",
sn_np->name, sensor_scenario, gpio_scenario);
SET_PIN_INIT(pdata, sensor_scenario, gpio_scenario);
num = of_get_child_count(sn_np);
node_table = kcalloc(num, sizeof(*node_table), GFP_KERNEL);
if (!node_table) {
err("out of memory for node_table[%s].", sn_np->name);
return -ENOMEM;
}
node_num = kcalloc(num, sizeof(*node_num), GFP_KERNEL);
if (!node_num) {
err("out of memory for node_num[%s].", sn_np->name);
kfree(node_table);
return -ENOMEM;
}
i = 0;
for_each_child_of_node(sn_np, seq_np) {
node_table[i] = seq_np;
ret = kstrtol(seq_np->name, 10, &node_num[i]);
if (ret) {
kfree(node_table);
kfree(node_num);
err("fail to kstrtol [%d]%s:%s.", i, sn_np->name, seq_np->name);
return ret;
}
i++;
}
/* sorting */
for (i = 0; i < num; i++) {
for (j = i + 1; j < num; j++) {
if (node_num[i] > node_num[j]) {
temp_node = node_table[i];
temp_num = node_num[i];
node_table[i] = node_table[j];
node_num[i] = node_num[j];
node_table[j] = temp_node;
node_num[j] = temp_num;
}
}
}
for (i = 0; i < num; i++) {
int gpio;
int idx_share;
int idx_seq;
int idx_prop;
struct exynos_sensor_pin *pin;
struct property *prop;
int length;
prop = of_find_property(node_table[i], "pname", &length);
if (!prop || length <= 1)
continue;
idx_seq = pdata->pinctrl_index[sensor_scenario][gpio_scenario];
pin = &pdata->pin_ctrls[sensor_scenario][gpio_scenario][idx_seq];
pdata->pinctrl_index[sensor_scenario][gpio_scenario]++;
/* of_get_named_gpio does not guarantee about device tree
* format for gpio.
*
* ex) { pname = "pin"; pin = <PIN_OUTPUT 0 0>; gpio = <&gpp 1 0x1>; };
*
* If do not describe property of gpio correctly,
* of_get_named_gpio is returned zero value.
* therefore, this need to prevent.
* length is depends on cell(size is 4) count.
*/
prop = of_find_property(node_table[i], "gpio", &length);
if (!prop || length < 12) {
pin->pin = -1;
} else {
gpio = of_get_named_gpio(node_table[i], "gpio", 0);
if (gpio_is_valid(gpio)) {
pin->pin = gpio;
gpio_request_one(gpio, GPIOF_OUT_INIT_LOW,
"CAM_GPIO_OUTPUT_LOW");
gpio_free(gpio);
}
}
of_property_read_string(node_table[i], "pname", (const char **)&pin->name);
idx_prop = 0;
of_property_read_u32_index(node_table[i], "pin", idx_prop++, &pin->act);
of_property_read_u32_index(node_table[i], "pin", idx_prop++, &pin->value);
of_property_read_u32_index(node_table[i], "pin", idx_prop++, &pin->delay);
of_property_read_u32_index(node_table[i], "pin", idx_prop++, &pin->voltage);
idx_prop = 0;
if (of_find_property(node_table[i], "share", NULL)) {
of_property_read_u32_index(node_table[i], "share", idx_prop++, &pin->shared_rsc_type);
of_property_read_u32_index(node_table[i], "share", idx_prop++, &idx_share);
of_property_read_u32_index(node_table[i], "share", idx_prop++, &pin->shared_rsc_active);
pin->shared_rsc_slock = &core->shared_rsc_slock[idx_share];
pin->shared_rsc_count = &core->shared_rsc_count[idx_share];
} else {
pin->shared_rsc_type = 0;
pin->shared_rsc_slock = NULL;
pin->shared_rsc_count = NULL;
pin->shared_rsc_active = 0;
}
if (of_find_property(node_table[i], "actuator_i2c_delay", NULL)) {
of_property_read_u32(node_table[i], "actuator_i2c_delay", &pin->actuator_i2c_delay);
}
if (pin->act == PIN_REGULATOR) {
bool reg_cap = true;
struct is_module_regulator *is_module_regulator;
struct device *dev = &core->pdev->dev;
struct regulator *regulator;
list_for_each_entry(is_module_regulator, &core->resourcemgr.regulator_list, list) {
if (!strcmp(is_module_regulator->name, pin->name)) {
reg_cap = false;
break;
}
}
if (reg_cap) {
is_module_regulator = kzalloc(sizeof(struct is_module_regulator), GFP_KERNEL);
if (!is_module_regulator) {
err("%s: failed to alloc is_regulator", __func__);
return -ENOMEM;
}
is_module_regulator->name = pin->name;
list_add_tail(&is_module_regulator->list, &core->resourcemgr.regulator_list);
dbg("%s is registered in regulator_list", is_module_regulator->name);
/* If sensor voltage source is already enabled due to specific reason.
* Set regulator_force_disable, then maintain initial state
*/
regulator = regulator_get_optional(dev, pin->name);
if (IS_ERR_OR_NULL(regulator)) {
err("%s: failed to get regulator", (pin->name == 0 ? "null" : pin->name));
return PTR_ERR(regulator);
}
if (regulator_is_enabled(regulator)) {
warn("regulator(%s) is already enabled, forcely disable\n", pin->name);
ret = regulator_force_disable(regulator);
if (ret)
err("regulator_force_disable fail(%d)\n", ret);
}
regulator_put(regulator);
}
}
dbg("%s: gpio=%d, name=%s, act=%d, val=%d, delay=%d, volt=%d, share=<%d %d>\n",
node_table[i]->name,
pin->pin,
pin->name,
pin->act,
pin->value,
pin->delay,
pin->voltage,
pin->shared_rsc_type,
pin->shared_rsc_active);
}
kfree(node_table);
kfree(node_num);
}
return 0;
}
static void is_module_match_seq_parse_dt(struct device_node *dnode,
struct exynos_platform_is_module *pdata)
{
struct device_node *match_np;
struct device_node *group_np;
int num_entry;
int i, j;
int idx_prop;
struct exynos_sensor_module_match *entry;
match_np = of_get_child_by_name(dnode, "match_seq");
if (!match_np)
return;
/*
* A match seq node is divided into group and entry.
* Group can be configured as many as MATCH_GROUP_MAX,
* and each group can have as many entries as MATCH_ENTRY_MAX.
* Each entry consists of a slave_addr, reg offset, number of byte, and expected value
* to compare the result with i2c transfer.
*/
i = 0;
for_each_child_of_node(match_np, group_np) {
num_entry = of_property_count_elems_of_size((group_np),
"entry", sizeof(u32)) / 5;
for (j = 0; j < num_entry; j++) {
entry = &pdata->match_entry[i][j];
idx_prop = j * 5;
of_property_read_u32_index(group_np, "entry", idx_prop++,
&entry->slave_addr);
of_property_read_u32_index(group_np, "entry", idx_prop++,
&entry->reg);
of_property_read_u32_index(group_np, "entry", idx_prop++,
&entry->reg_type);
of_property_read_u32_index(group_np, "entry", idx_prop++,
&entry->expected_data);
of_property_read_u32_index(group_np, "entry", idx_prop++,
&entry->data_type);
probe_info("%s: slave_addr(0x%04x), reg(0x%04x), reg_type(%d), \
expected_data(0x%04x), data_type(%d)\n",
__func__, entry->slave_addr, entry->reg,
entry->reg_type, entry->expected_data,
entry->data_type);
}
pdata->num_of_match_entry[i++] = num_entry;
}
pdata->num_of_match_groups = i;
}
int is_sensor_module_parse_dt(struct device *dev,
int (*module_callback)(struct device *, struct exynos_platform_is_module *))
{
int ret;
struct exynos_platform_is_module *pdata;
struct device_node *dnode;
struct device_node *power_np;
u32 use = 0;
FIMC_BUG(!dev);
FIMC_BUG(!dev->of_node);
dnode = dev->of_node;
pdata = kzalloc(sizeof(struct exynos_platform_is_module), GFP_KERNEL);
if (!pdata) {
probe_err("%s: no memory for platform data", __func__);
return -ENOMEM;
}
is_get_gpio_ops(pdata);
ret = is_board_cfg_parse_dt(dnode, pdata);
if (ret)
goto p_err;
is_module_cfg_parse_dt(dnode, pdata);
is_module_rom_parse_dt(dnode, pdata);
is_module_peris_parse_dt(dnode, pdata);
ret = is_cis_vc_extra_parse_dt(dnode, pdata);
if (ret)
goto p_err;
ret = is_cis_modes_parse_dt(dnode, pdata);
if (ret)
goto p_err;
power_np = of_get_child_by_name(dnode, "power_seq");
if (power_np) {
ret = of_property_read_u32(power_np, "use", &use);
if (ret)
probe_warn("use read is skipped");
}
if (power_np && use) {
ret = parse_power_seq_data(pdata, power_np);
if (ret) {
probe_err("%s: parse_power_seq_data(%d)", power_np->full_name, ret);
goto p_err;
}
} else {
if (module_callback) {
ret = module_callback(dev, pdata);
if (ret) {
probe_err("sensor dt callback is fail(%d)", ret);
goto p_err;
}
} else {
ret = -EINVAL;
probe_err("sensor dt callback is NULL");
goto p_err;
}
}
is_module_match_seq_parse_dt(dnode, pdata);
pdata->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(pdata->pinctrl)) {
probe_err("devm_pinctrl_get is fail");
goto p_err;
}
ret = get_pin_lookup_state(pdata->pinctrl, pdata->pin_ctrls);
if (ret) {
probe_err("get_pin_lookup_state is fail(%d)", ret);
goto p_err;
}
dev->platform_data = pdata;
return 0;
p_err:
kfree(pdata);
return ret;
}
#if IS_ENABLED(CONFIG_SPI)
int is_spi_dev_parse_dt(struct is_spi *spi)
{
int ret = 0;
struct device_node *np;
struct device *dev;
struct pinctrl_state *s;
FIMC_BUG(!spi);
dev = &spi->device->dev;
np = of_find_compatible_node(NULL,NULL, spi->node);
if(np == NULL) {
probe_err("compatible: fail to read, spi_parse_dt");
ret = -ENODEV;
goto p_err;
}
spi->use_spi_pinctrl = of_property_read_bool(np, "use_spi_pinctrl");
if (!spi->use_spi_pinctrl) {
probe_info("%s: spi dt parsing skipped\n", __func__);
goto p_err;
}
spi->pinctrl = devm_pinctrl_get(dev);
if (IS_ERR(spi->pinctrl)) {
probe_err("devm_pinctrl_get is fail");
goto p_err;
}
s = pinctrl_lookup_state(spi->pinctrl, "ssn_out");
if (IS_ERR_OR_NULL(s)) {
probe_info("pinctrl_lookup_state(%s) is not found", "ssn_out");
spi->pin_ssn_out = NULL;
} else {
spi->pin_ssn_out = s;
}
s = pinctrl_lookup_state(spi->pinctrl, "ssn_fn");
if (IS_ERR_OR_NULL(s)) {
probe_info("pinctrl_lookup_state(%s) is not found", "ssn_fn");
spi->pin_ssn_fn = NULL;
} else {
spi->pin_ssn_fn = s;
}
s = pinctrl_lookup_state(spi->pinctrl, "ssn_inpd");
if (IS_ERR_OR_NULL(s)) {
probe_info("pinctrl_lookup_state(%s) is not found", "ssn_inpd");
spi->pin_ssn_inpd = NULL;
} else {
spi->pin_ssn_inpd = s;
}
s = pinctrl_lookup_state(spi->pinctrl, "ssn_inpu");
if (IS_ERR_OR_NULL(s)) {
probe_info("pinctrl_lookup_state(%s) is not found", "ssn_inpu");
spi->pin_ssn_inpu = NULL;
} else {
spi->pin_ssn_inpu = s;
}
spi->parent_pinctrl = devm_pinctrl_get(spi->device->dev.parent->parent);
s = pinctrl_lookup_state(spi->parent_pinctrl, "spi_out");
if (IS_ERR_OR_NULL(s)) {
err("pinctrl_lookup_state(%s) is failed", "spi_out");
ret = -EINVAL;
goto p_err;
}
spi->parent_pin_out = s;
s = pinctrl_lookup_state(spi->parent_pinctrl, "spi_fn");
if (IS_ERR_OR_NULL(s)) {
err("pinctrl_lookup_state(%s) is failed", "spi_fn");
ret = -EINVAL;
goto p_err;
}
spi->parent_pin_fn = s;
p_err:
return ret;
}
#endif /* CONFIG_SPI */
#endif /* CONFIG_OF */