/* * 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 #include #include #include #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 = ; 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 */