int get_sony_hw(void)
{
	int ret = 0;
	struct device_node *dt_root;
	int i, j, count = 0;
	const char *dt_space_no = NULL;

	if (_sony_hw != HW_UNKNOWN)
		return _sony_hw;

	dt_root = of_find_node_by_path("/");
	count = of_property_count_strings(dt_root, "somc,space-no");

	if (count <= 0)
		return HW_UNKNOWN;

	for (i = 0; i < count; i++) {
		ret = of_property_read_string_index(dt_root,
				"somc,space-no", i, &dt_space_no);
		if (ret < 0)
			continue;

		for (j = 0; j < ARRAY_SIZE(sony_hw_map); j++) {
			if (!strcmp(dt_space_no, sony_hw_map[j].space_no)) {
				_sony_hw = sony_hw_map[j].hw;
				break;
			};
		};
	};

	return _sony_hw;
}
Beispiel #2
0
static int sirfsoc_dt_node_to_map(struct pinctrl_dev *pctldev,
				 struct device_node *np_config,
				 struct pinctrl_map **map, unsigned *num_maps)
{
	struct sirfsoc_pmx *spmx = pinctrl_dev_get_drvdata(pctldev);
	struct device_node *np;
	struct property *prop;
	const char *function, *group;
	int ret, index = 0, count = 0;

	/* calculate number of maps required */
	for_each_child_of_node(np_config, np) {
		ret = of_property_read_string(np, "sirf,function", &function);
		if (ret < 0) {
			of_node_put(np);
			return ret;
		}

		ret = of_property_count_strings(np, "sirf,pins");
		if (ret < 0) {
			of_node_put(np);
			return ret;
		}

		count += ret;
	}
Beispiel #3
0
static int scpi_clk_add(struct device *dev, struct device_node *np,
			const struct of_device_id *match)
{
	struct clk **clks;
	int idx, count;
	struct scpi_clk_data *clk_data;

	count = of_property_count_strings(np, "clock-output-names");
	if (count < 0) {
		dev_err(dev, "%s: invalid clock output count\n", np->name);
		return -EINVAL;
	}

	clk_data = devm_kmalloc(dev, sizeof(*clk_data), GFP_KERNEL);
	if (!clk_data)
		return -ENOMEM;

	clk_data->clk_num = count;
	clk_data->clk = devm_kcalloc(dev, count, sizeof(*clk_data->clk),
				     GFP_KERNEL);
	if (!clk_data->clk)
		return -ENOMEM;

	clks = devm_kcalloc(dev, count, sizeof(*clks), GFP_KERNEL);
	if (!clks)
		return -ENOMEM;

	for (idx = 0; idx < count; idx++) {
		struct scpi_clk *sclk;
		const char *name;
		u32 val;

		sclk = devm_kzalloc(dev, sizeof(*sclk), GFP_KERNEL);
		if (!sclk)
			return -ENOMEM;

		if (of_property_read_string_index(np, "clock-output-names",
						  idx, &name)) {
			dev_err(dev, "invalid clock name @ %s\n", np->name);
			return -EINVAL;
		}

		if (of_property_read_u32_index(np, "clock-indices",
					       idx, &val)) {
			dev_err(dev, "invalid clock index @ %s\n", np->name);
			return -EINVAL;
		}

		sclk->id = val;

		clks[idx] = scpi_clk_ops_init(dev, match, sclk, name);
		if (IS_ERR_OR_NULL(clks[idx]))
			dev_err(dev, "failed to register clock '%s'\n", name);
		else
			dev_dbg(dev, "Registered clock '%s'\n", name);
		clk_data->clk[idx] = sclk;
	}

	return of_clk_add_provider(np, scpi_of_clk_src_get, clk_data);
}
static int of_get_qcom_regulator_init_data(struct device *dev,
					struct regulator_init_data **init_data)
{
	struct device_node *node = dev->of_node;
	struct regulator_consumer_supply *consumer_supplies;
	int i, rc, num_consumer_supplies, array_len;

	array_len = of_property_count_strings(node, consumer_supply_prop_name);
	if (array_len > 0) {
		
		if (array_len & 1) {
			dev_err(dev, "error: %s device node property value "
				"contains an odd number of elements: %d\n",
				consumer_supply_prop_name, array_len);
			return -EINVAL;
		}
		num_consumer_supplies = array_len / 2;

		consumer_supplies = devm_kzalloc(dev,
			sizeof(struct regulator_consumer_supply)
			* num_consumer_supplies, GFP_KERNEL);
		if (consumer_supplies == NULL) {
			dev_err(dev, "devm_kzalloc failed\n");
			return -ENOMEM;
		}

		for (i = 0; i < num_consumer_supplies; i++) {
			rc = of_property_read_string_index(node,
				consumer_supply_prop_name, i * 2,
				&consumer_supplies[i].supply);
			if (rc) {
				dev_err(dev, "of_property_read_string_index "
					"failed, rc=%d\n", rc);
				devm_kfree(dev, consumer_supplies);
				return rc;
			}

			rc = of_property_read_string_index(node,
				consumer_supply_prop_name, (i * 2) + 1,
				&consumer_supplies[i].dev_name);
			if (rc) {
				dev_err(dev, "of_property_read_string_index "
					"failed, rc=%d\n", rc);
				devm_kfree(dev, consumer_supplies);
				return rc;
			}

			
			if (strnlen(consumer_supplies[i].dev_name,
					MAX_DEV_NAME_LEN) == 0)
				consumer_supplies[i].dev_name = NULL;
		}

		(*init_data)->consumer_supplies = consumer_supplies;
		(*init_data)->num_consumer_supplies = num_consumer_supplies;
	}

	return 0;
}
Beispiel #5
0
static int nokia_modem_gpio_probe(struct device *dev)
{
	struct device_node *np = dev->of_node;
	struct nokia_modem_device *modem = dev_get_drvdata(dev);
	int gpio_count, gpio_name_count, i, err;

	gpio_count = of_gpio_count(np);

	if (gpio_count < 0) {
		dev_err(dev, "missing gpios: %d\n", gpio_count);
		return gpio_count;
	}

	gpio_name_count = of_property_count_strings(np, "gpio-names");

	if (gpio_count != gpio_name_count) {
		dev_err(dev, "number of gpios does not equal number of gpio names\n");
		return -EINVAL;
	}

	modem->gpios = devm_kzalloc(dev, gpio_count *
				sizeof(struct nokia_modem_gpio), GFP_KERNEL);
	if (!modem->gpios) {
		dev_err(dev, "Could not allocate memory for gpios\n");
		return -ENOMEM;
	}

	modem->gpio_amount = gpio_count;

	for (i = 0; i < gpio_count; i++) {
		modem->gpios[i].gpio = devm_gpiod_get_index(dev, NULL, i);
		if (IS_ERR(modem->gpios[i].gpio)) {
			dev_err(dev, "Could not get gpio %d\n", i);
			return PTR_ERR(modem->gpios[i].gpio);
		}

		err = of_property_read_string_index(np, "gpio-names", i,
						&(modem->gpios[i].name));
		if (err) {
			dev_err(dev, "Could not get gpio name %d\n", i);
			return err;
		}

		err = gpiod_direction_output(modem->gpios[i].gpio, 0);
		if (err)
			return err;

		err = gpiod_export(modem->gpios[i].gpio, 0);
		if (err)
			return err;

		err = gpiod_export_link(dev, modem->gpios[i].name,
							modem->gpios[i].gpio);
		if (err)
			return err;
	}

	return 0;
}
Beispiel #6
0
/**
 * omap_device_build_from_dt - build an omap_device with multiple hwmods
 * @pdev_name: name of the platform_device driver to use
 * @pdev_id: this platform_device's connection ID
 * @oh: ptr to the single omap_hwmod that backs this omap_device
 * @pdata: platform_data ptr to associate with the platform_device
 * @pdata_len: amount of memory pointed to by @pdata
 *
 * Function for building an omap_device already registered from device-tree
 *
 * Returns 0 or PTR_ERR() on error.
 */
static int omap_device_build_from_dt(struct platform_device *pdev)
{
	struct omap_hwmod **hwmods;
	struct omap_device *od;
	struct omap_hwmod *oh;
	struct device_node *node = pdev->dev.of_node;
	const char *oh_name;
	int oh_cnt, i, ret = 0;

	oh_cnt = of_property_count_strings(node, "ti,hwmods");
	if (!oh_cnt || IS_ERR_VALUE(oh_cnt)) {
		dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
		return -ENODEV;
	}

	hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
	if (!hwmods) {
		ret = -ENOMEM;
		goto odbfd_exit;
	}

	for (i = 0; i < oh_cnt; i++) {
		of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
		oh = omap_hwmod_lookup(oh_name);
		if (!oh) {
			dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
				oh_name);
			ret = -EINVAL;
			goto odbfd_exit1;
		}
		hwmods[i] = oh;
	}

	od = omap_device_alloc(pdev, hwmods, oh_cnt);
	if (!od) {
		dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
			oh_name);
		ret = PTR_ERR(od);
		goto odbfd_exit1;
	}

	/* Fix up missing resource names */
	for (i = 0; i < pdev->num_resources; i++) {
		struct resource *r = &pdev->resource[i];

		if (r->name == NULL)
			r->name = dev_name(&pdev->dev);
	}

	if (of_get_property(node, "ti,no_idle_on_suspend", NULL))
		omap_device_disable_idle_on_suspend(pdev);

	pdev->dev.pm_domain = &omap_device_pm_domain;

odbfd_exit1:
	kfree(hwmods);
odbfd_exit:
	return ret;
}
static int mitigate_inrush_probe(struct platform_device *pdev)
{
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	int i, retval;
	struct subsystem *subsys;
	struct inrush_driver_data *drv_data;

	retval = of_property_count_strings(np,
					"qcom,dependent-subsystems");
	if (IS_ERR_VALUE(retval)) {
		dev_err(dev, "Failed to get dependent subsystems\n");
		return -EINVAL;
	}

	drv_data = kzalloc((retval * sizeof(struct subsystem) +
			sizeof(struct inrush_driver_data)), GFP_KERNEL);

	if (!drv_data)
		return -ENOMEM;

	drv_data->subsystems = (void *)drv_data +
				sizeof(struct inrush_driver_data);
	drv_data->subsys_count = retval;

	for (i = 0; i < drv_data->subsys_count; i++) {
		subsys = &drv_data->subsystems[i];
		subsys->drv_data = drv_data;
		of_property_read_string_index(np, "qcom,dependent-subsystems",
					i, &subsys->name);
		subsys->nb.notifier_call = mitigate_inrush_notifier_cb;
		subsys->notif_handle =
			subsys_notif_register_notifier(subsys->name,
							&subsys->nb);
		if (IS_ERR(subsys->notif_handle)) {
			dev_err(dev, "Notifier registration failed for %s\n",
						 subsys->name);
			retval = PTR_ERR(subsys->notif_handle);
			goto err_subsys_notif;
		}
	}

	drv_data->vreg = devm_regulator_get(dev, "vdd");
	if (IS_ERR(drv_data->vreg)) {
		dev_err(dev, "Failed to get regulator\n");
		return PTR_ERR(drv_data->vreg);
	}

	return 0;

err_subsys_notif:
	for (i = 0; i < drv_data->subsys_count; i++) {
		subsys = &drv_data->subsystems[i];
		subsys_notif_unregister_notifier(subsys->notif_handle,
						&subsys->nb);
	}
	kfree(drv_data);
	return retval;
}
Beispiel #8
0
int msm_ispif_get_ahb_clk_info(struct ispif_device *ispif_dev,
	struct platform_device *pdev,
	struct msm_cam_clk_info *ahb_clk_info)
{
	uint32_t count, num_ahb_clk = 0;
	int i, rc;
	uint32_t rates[ISPIF_CLK_INFO_MAX];

	struct device_node *of_node;
	of_node = pdev->dev.of_node;

	count = of_property_count_strings(of_node, "clock-names");

	CDBG("count = %d\n", count);
	if (count == 0) {
		pr_err("no clocks found in device tree, count=%d", count);
		return 0;
	}

	if (count > ISPIF_CLK_INFO_MAX) {
		pr_err("invalid count=%d, max is %d\n", count,
			ISPIF_CLK_INFO_MAX);
		return -EINVAL;
	}

	rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
		rates, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		return rc;
	}
	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node, "clock-names",
				i, &(ahb_clk_info[num_ahb_clk].clk_name));
		CDBG("clock-names[%d] = %s\n",
			 i, ahb_clk_info[i].clk_name);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			return rc;
		}
		if (strnstr(ahb_clk_info[num_ahb_clk].clk_name, "ahb",
			sizeof(ahb_clk_info[num_ahb_clk].clk_name))) {
			ahb_clk_info[num_ahb_clk].clk_rate =
				(rates[i] == 0) ? (long)-1 : rates[i];
			CDBG("clk_rate[%d] = %ld\n", i,
				ahb_clk_info[i].clk_rate);
			num_ahb_clk++;
		}
	}
	ispif_dev->num_ahb_clk = num_ahb_clk;
	return 0;
}
Beispiel #9
0
static struct mmi_factory_info *mmi_parse_of(struct platform_device *pdev)
{
	struct mmi_factory_info *info;
	int gpio_count;
	struct device_node *np = pdev->dev.of_node;
	int i;
	enum of_gpio_flags flags;

	if (!np) {
		dev_err(&pdev->dev, "No OF DT node found.\n");
		return NULL;
	}

	gpio_count = of_gpio_count(np);

	if (!gpio_count) {
		dev_err(&pdev->dev, "No GPIOS defined.\n");
		return NULL;
	}

	/* Make sure number of GPIOs defined matches the supplied number of
	 * GPIO name strings.
	 */
	if (gpio_count != of_property_count_strings(np, "gpio-names")) {
		dev_err(&pdev->dev, "GPIO info and name mismatch\n");
		return NULL;
	}

	info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
	if (!info)
		return NULL;

	info->list = devm_kzalloc(&pdev->dev,
				sizeof(struct gpio) * gpio_count,
				GFP_KERNEL);
	if (!info->list)
		return NULL;

	info->num_gpios = gpio_count;
	for (i = 0; i < gpio_count; i++) {
		info->list[i].gpio = of_get_gpio_flags(np, i, &flags);
		info->list[i].flags = flags;
		of_property_read_string_index(np, "gpio-names", i,
						&info->list[i].label);
		dev_dbg(&pdev->dev, "GPIO: %d  FLAGS: %ld  LABEL: %s\n",
			info->list[i].gpio, info->list[i].flags,
			info->list[i].label);
	}

	return info;
}
Beispiel #10
0
/**
 * of_dma_request_slave_channel - Get the DMA slave channel
 * @np:		device node to get DMA request from
 * @name:	name of desired channel
 *
 * Returns pointer to appropriate DMA channel on success or an error pointer.
 */
struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
					      const char *name)
{
	struct of_phandle_args	dma_spec;
	struct of_dma		*ofdma;
	struct dma_chan		*chan;
	int			count, i;
	int			ret_no_channel = -ENODEV;

	if (!np || !name) {
		pr_err("%s: not enough information provided\n", __func__);
		return ERR_PTR(-ENODEV);
	}

	/* Silently fail if there is not even the "dmas" property */
	if (!of_find_property(np, "dmas", NULL))
		return ERR_PTR(-ENODEV);

	count = of_property_count_strings(np, "dma-names");
	if (count < 0) {
		pr_err("%s: dma-names property of node '%s' missing or empty\n",
			__func__, np->full_name);
		return ERR_PTR(-ENODEV);
	}

	for (i = 0; i < count; i++) {
		if (of_dma_match_channel(np, name, i, &dma_spec))
			continue;

		mutex_lock(&of_dma_lock);
		ofdma = of_dma_find_controller(&dma_spec);

		if (ofdma) {
			chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
		} else {
			ret_no_channel = -EPROBE_DEFER;
			chan = NULL;
		}

		mutex_unlock(&of_dma_lock);

		of_node_put(dma_spec.np);

		if (chan)
			return chan;
	}

	return ERR_PTR(ret_no_channel);
}
static int msm_jpeg_get_clk_info(struct msm_jpeg_device *jpeg_dev,
	struct platform_device *pdev)
{
	uint32_t count;
	int i, rc;
	uint32_t rates[JPEG_CLK_INFO_MAX];

	struct device_node *of_node;
	of_node = pdev->dev.of_node;

	count = of_property_count_strings(of_node, "clock-names");

	JPEG_DBG("count = %d\n", count);
	if (count == 0) {
		pr_err("no clocks found in device tree, count=%d", count);
		return 0;
	}

	if (count > JPEG_CLK_INFO_MAX) {
		pr_err("invalid count=%d, max is %d\n", count,
			JPEG_CLK_INFO_MAX);
		return -EINVAL;
	}

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node, "clock-names",
				i, &(jpeg_8x_clk_info[i].clk_name));
		JPEG_DBG("clock-names[%d] = %s\n",
			 i, jpeg_8x_clk_info[i].clk_name);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			return rc;
		}
	}
	rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
		rates, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		return rc;
	}
	for (i = 0; i < count; i++) {
		jpeg_8x_clk_info[i].clk_rate =
			(rates[i] == 0) ? -1 : rates[i];
		JPEG_DBG("clk_rate[%d] = %ld\n",
			i, jpeg_8x_clk_info[i].clk_rate);
	}
	jpeg_dev->num_clk = count;
	return 0;
}
Beispiel #12
0
/**
 * fwnode_property_read_string_array - return string array property of a node
 * @fwnode: Firmware node to get the property of
 * @propname: Name of the property
 * @val: The values are stored here or %NULL to return the number of values
 * @nval: Size of the @val array
 *
 * Read an string list property @propname from the given firmware node and store
 * them to @val if found.
 *
 * Return: number of values if @val was %NULL,
 *         %0 if the property was found (success),
 *	   %-EINVAL if given arguments are not valid,
 *	   %-ENODATA if the property does not have a value,
 *	   %-EPROTO if the property is not an array of strings,
 *	   %-EOVERFLOW if the size of the property is not as expected,
 *	   %-ENXIO if no suitable firmware interface is present.
 */
int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
                                      const char *propname, const char **val,
                                      size_t nval)
{
    if (is_of_node(fwnode))
        return val ?
               of_property_read_string_array(to_of_node(fwnode),
                                             propname, val, nval) :
               of_property_count_strings(to_of_node(fwnode), propname);
    else if (is_acpi_node(fwnode))
        return acpi_dev_prop_read(to_acpi_node(fwnode), propname,
                                  DEV_PROP_STRING, val, nval);

    return pset_prop_read_array(to_pset(fwnode), propname,
                                DEV_PROP_STRING, val, nval);
}
Beispiel #13
0
int axidma_of_num_channels(struct platform_device *pdev)
{
    int num_dmas, num_dma_names;
    struct device_node *driver_node;

    // Get the device tree node for the driver
    driver_node = pdev->dev.of_node;

    // Check that the device tree node has the 'dmas' and 'dma-names' properties
    if (of_find_property(driver_node, "dma-names", NULL) == NULL) {
        axidma_node_err(driver_node, "Property 'dma-names' is missing.\n");
        return -EINVAL;
    } else if (of_find_property(driver_node, "dmas", NULL) == NULL) {
        axidma_node_err(driver_node, "Property 'dmas' is missing.\n");
        return -EINVAL;
    }

    // Get the length of the properties, and make sure they are not empty
    num_dma_names = of_property_count_strings(driver_node, "dma-names");
    if (num_dma_names < 0) {
        axidma_node_err(driver_node, "Unable to get the 'dma-names' property "
                        "length.\n");
        return -EINVAL;
    } else if (num_dma_names == 0) {
        axidma_node_err(driver_node, "'dma-names' property is empty.\n");
        return -EINVAL;
    }
    num_dmas = of_count_phandle_with_args(driver_node, "dmas", "#dma-cells");
    if (num_dmas < 0) {
        axidma_node_err(driver_node, "Unable to get the 'dmas' property "
                        "length.\n");
        return -EINVAL;
    } else if (num_dmas == 0) {
        axidma_node_err(driver_node, "'dmas' property is empty.\n");
        return -EINVAL;
    }

    // Check that the number of entries in each property matches
    if (num_dma_names != num_dmas) {
        axidma_node_err(driver_node, "Length of 'dma-names' and 'dmas' "
                        "properties differ.\n");
        return -EINVAL;
    }

    return num_dma_names;
}
static int of_get_eq_pdata(struct tas57xx_platform_data *pdata, struct device_node* p_node)
{
	int i, ret = 0, length = 0;
	const char *str = NULL;
	char *regs = NULL;

	prob_priv.num_eq = of_property_count_strings(p_node,"eq_name");
	if(prob_priv.num_eq <= 0){
		printk("no of eq_name config\n");
		ret = -ENODEV;
		goto exit;
	}

	pdata->num_eq_cfgs = prob_priv.num_eq;

	prob_priv.eq_configs = kzalloc(prob_priv.num_eq * sizeof(struct tas57xx_eq_cfg), GFP_KERNEL);

	for(i = 0; i < prob_priv.num_eq; i++){
		ret = of_property_read_string_index(p_node, "eq_name", i , &str);

		if(of_find_property(p_node, "eq_table", &length) == NULL){
			printk("%s fail to get of eq_table\n", __func__);
			goto exit1;
		}

		regs = kzalloc(length * sizeof(char *), GFP_KERNEL);
		if (!regs) {
			printk("ERROR, NO enough mem for eq_table!\n");
			return -ENOMEM;
		}

		ret = of_property_read_u8_array(p_node, "eq_table", regs, length);

		strncpy(prob_priv.eq_configs[i].name, str, NAME_SIZE);
		prob_priv.eq_configs[i].regs = regs;
	}

	pdata->eq_cfgs = prob_priv.eq_configs;

	return 0;
exit1:
	kfree(prob_priv.eq_configs);
exit:
	return ret;
}
static int of_read_clocks(struct device *dev, struct clk ***clks_ref,
			  const char *propname)
{
	int clk_count, i, len;
	struct clk **clks;

	if (!of_find_property(dev->of_node, propname, &len))
		return 0;

	clk_count = of_property_count_strings(dev->of_node, propname);
	if (IS_ERR_VALUE(clk_count)) {
		dev_err(dev, "Failed to get clock names\n");
		return -EINVAL;
	}

	clks = devm_kzalloc(dev, sizeof(struct clk *) * clk_count,
				GFP_KERNEL);
	if (!clks)
		return -ENOMEM;

	for (i = 0; i < clk_count; i++) {
		const char *clock_name;
		of_property_read_string_index(dev->of_node,
					      propname, i,
					      &clock_name);

		clks[i] = devm_clk_get(dev, clock_name);
		if (IS_ERR(clks[i])) {
			int rc = PTR_ERR(clks[i]);
			if (rc != -EPROBE_DEFER)
				dev_err(dev, "Failed to get %s clock\n",
								clock_name);
			return rc;
		}

		/* Make sure rate-settable clocks' rates are set */
		if (clk_get_rate(clks[i]) == 0)
			clk_set_rate(clks[i], clk_round_rate(clks[i],
								XO_FREQ));
	}

	*clks_ref = clks;
	return clk_count;
}
Beispiel #16
0
/**
 * of_dma_request_slave_channel - Get the DMA slave channel
 * @np:		device node to get DMA request from
 * @name:	name of desired channel
 *
 * Returns pointer to appropriate dma channel on success or NULL on error.
 */
struct dma_chan *of_dma_request_slave_channel(struct device_node *np,
					      const char *name)
{
	struct of_phandle_args	dma_spec;
	struct of_dma		*ofdma;
	struct dma_chan		*chan;
	int			count, i;

	if (!np || !name) {
		pr_err("%s: not enough information provided\n", __func__);
		return NULL;
	}

	count = of_property_count_strings(np, "dma-names");
	if (count < 0) {
		pr_err("%s: dma-names property missing or empty\n", __func__);
		return NULL;
	}

	for (i = 0; i < count; i++) {
		if (of_dma_match_channel(np, name, i, &dma_spec))
			continue;

		mutex_lock(&of_dma_lock);
		ofdma = of_dma_find_controller(&dma_spec);

		if (ofdma)
			chan = ofdma->of_dma_xlate(&dma_spec, ofdma);
		else
			chan = NULL;

		mutex_unlock(&of_dma_lock);

		of_node_put(dma_spec.np);

		if (chan)
			return chan;
	}

	return NULL;
}
Beispiel #17
0
static int __fwnode_property_read_string_array(struct fwnode_handle *fwnode,
					       const char *propname,
					       const char **val, size_t nval)
{
	if (is_of_node(fwnode))
		return val ?
			of_property_read_string_array(to_of_node(fwnode),
						      propname, val, nval) :
			of_property_count_strings(to_of_node(fwnode), propname);
	else if (is_acpi_node(fwnode))
		return acpi_node_prop_read(fwnode, propname, DEV_PROP_STRING,
					   val, nval);
	else if (is_pset_node(fwnode))
		return val ?
			pset_prop_read_string_array(to_pset_node(fwnode),
						    propname, val, nval) :
			pset_prop_count_elems_of_size(to_pset_node(fwnode),
						      propname,
						      sizeof(const char *));
	return -ENXIO;
}
Beispiel #18
0
static void siw_touch_of_array(struct device *dev, void *np,
					void *string, const char **name, int *cnt)
{
	int i;
	int ret = 0;

	(*cnt) = 0;

	ret = of_property_count_strings(np, string);
	if (ret < 0) {
		t_dev_warn(dev, "of count : %s not found\n", (char *)string);
		return;
	}

	(*cnt) = ret;
	t_dev_dbg_of(dev, "of count : %s, %d\n", (char *)string, (*cnt));
	for (i = 0; i < (*cnt); i++) {
		ret = of_property_read_string_index(np, string, i, (const char **)&name[i]);
		if (!ret) {
			t_dev_info(dev, "of string[%d/%d] : %s\n", i+1, (*cnt), name[i]);
		}
	}
}
Beispiel #19
0
static void __init lpc18xx_ccu_init(struct device_node *np)
{
	struct lpc18xx_branch_clk_data *clk_data;
	void __iomem *reg_base;
	int i, ret;

	reg_base = of_iomap(np, 0);
	if (!reg_base) {
		pr_warn("%s: failed to map address range\n", __func__);
		return;
	}

	clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL);
	if (!clk_data)
		return;

	clk_data->num = of_property_count_strings(np, "clock-names");
	clk_data->name = kcalloc(clk_data->num, sizeof(char *), GFP_KERNEL);
	if (!clk_data->name) {
		kfree(clk_data);
		return;
	}

	for (i = 0; i < clk_data->num; i++) {
		ret = of_property_read_string_index(np, "clock-names", i,
						    &clk_data->name[i]);
		if (ret) {
			pr_warn("%s: failed to get clock name at idx %d\n",
				__func__, i);
			continue;
		}

		lpc18xx_ccu_register_branch_clks(reg_base, clk_data->name[i]);
	}

	of_clk_add_provider(np, lpc18xx_ccu_branch_clk_get, clk_data);
}
static void __init of_selftest_property_string(void)
{
	const char *strings[4];
	struct device_node *np;
	int rc;

	pr_info("start\n");
	np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a");
	if (!np) {
		pr_err("No testcase data in device tree\n");
		return;
	}

	rc = of_property_match_string(np, "phandle-list-names", "first");
	selftest(rc == 0, "first expected:0 got:%i\n", rc);
	rc = of_property_match_string(np, "phandle-list-names", "second");
	selftest(rc == 1, "second expected:0 got:%i\n", rc);
	rc = of_property_match_string(np, "phandle-list-names", "third");
	selftest(rc == 2, "third expected:0 got:%i\n", rc);
	rc = of_property_match_string(np, "phandle-list-names", "fourth");
	selftest(rc == -ENODATA, "unmatched string; rc=%i\n", rc);
	rc = of_property_match_string(np, "missing-property", "blah");
	selftest(rc == -EINVAL, "missing property; rc=%i\n", rc);
	rc = of_property_match_string(np, "empty-property", "blah");
	selftest(rc == -ENODATA, "empty property; rc=%i\n", rc);
	rc = of_property_match_string(np, "unterminated-string", "blah");
	selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);

	/* of_property_count_strings() tests */
	rc = of_property_count_strings(np, "string-property");
	selftest(rc == 1, "Incorrect string count; rc=%i\n", rc);
	rc = of_property_count_strings(np, "phandle-list-names");
	selftest(rc == 3, "Incorrect string count; rc=%i\n", rc);
	rc = of_property_count_strings(np, "unterminated-string");
	selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
	rc = of_property_count_strings(np, "unterminated-string-list");
	selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);

	/* of_property_read_string_index() tests */
	rc = of_property_read_string_index(np, "string-property", 0, strings);
	selftest(rc == 0 && !strcmp(strings[0], "foobar"), "of_property_read_string_index() failure; rc=%i\n", rc);
	strings[0] = NULL;
	rc = of_property_read_string_index(np, "string-property", 1, strings);
	selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
	rc = of_property_read_string_index(np, "phandle-list-names", 0, strings);
	selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
	rc = of_property_read_string_index(np, "phandle-list-names", 1, strings);
	selftest(rc == 0 && !strcmp(strings[0], "second"), "of_property_read_string_index() failure; rc=%i\n", rc);
	rc = of_property_read_string_index(np, "phandle-list-names", 2, strings);
	selftest(rc == 0 && !strcmp(strings[0], "third"), "of_property_read_string_index() failure; rc=%i\n", rc);
	strings[0] = NULL;
	rc = of_property_read_string_index(np, "phandle-list-names", 3, strings);
	selftest(rc == -ENODATA && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
	strings[0] = NULL;
	rc = of_property_read_string_index(np, "unterminated-string", 0, strings);
	selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
	rc = of_property_read_string_index(np, "unterminated-string-list", 0, strings);
	selftest(rc == 0 && !strcmp(strings[0], "first"), "of_property_read_string_index() failure; rc=%i\n", rc);
	strings[0] = NULL;
	rc = of_property_read_string_index(np, "unterminated-string-list", 2, strings); /* should fail */
	selftest(rc == -EILSEQ && strings[0] == NULL, "of_property_read_string_index() failure; rc=%i\n", rc);
	strings[1] = NULL;

	/* of_property_read_string_array() tests */
	rc = of_property_read_string_array(np, "string-property", strings, 4);
	selftest(rc == 1, "Incorrect string count; rc=%i\n", rc);
	rc = of_property_read_string_array(np, "phandle-list-names", strings, 4);
	selftest(rc == 3, "Incorrect string count; rc=%i\n", rc);
	rc = of_property_read_string_array(np, "unterminated-string", strings, 4);
	selftest(rc == -EILSEQ, "unterminated string; rc=%i\n", rc);
	/* -- An incorrectly formed string should cause a failure */
	rc = of_property_read_string_array(np, "unterminated-string-list", strings, 4);
	selftest(rc == -EILSEQ, "unterminated string array; rc=%i\n", rc);
	/* -- parsing the correctly formed strings should still work: */
	strings[2] = NULL;
	rc = of_property_read_string_array(np, "unterminated-string-list", strings, 2);
	selftest(rc == 2 && strings[2] == NULL, "of_property_read_string_array() failure; rc=%i\n", rc);
	strings[1] = NULL;
	rc = of_property_read_string_array(np, "phandle-list-names", strings, 1);
	selftest(rc == 1 && strings[1] == NULL, "Overwrote end of string array; rc=%i, str='%s'\n", rc, strings[1]);
}
Beispiel #21
0
static int gdsc_probe(struct platform_device *pdev)
{
	static atomic_t gdsc_count = ATOMIC_INIT(-1);
	struct regulator_config reg_config = {};
	struct regulator_init_data *init_data;
	struct resource *res;
	struct gdsc *sc;
	uint32_t regval;
	bool retain_mem, retain_periph, support_hw_trigger;
	int i, ret;

	sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
	if (sc == NULL)
		return -ENOMEM;

	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
	if (init_data == NULL)
		return -ENOMEM;

	if (of_get_property(pdev->dev.of_node, "parent-supply", NULL))
		init_data->supply_regulator = "parent";

	ret = of_property_read_string(pdev->dev.of_node, "regulator-name",
				      &sc->rdesc.name);
	if (ret)
		return ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL)
		return -EINVAL;
	sc->gdscr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
	if (sc->gdscr == NULL)
		return -ENOMEM;

	sc->clock_count = of_property_count_strings(pdev->dev.of_node,
					    "clock-names");
	if (sc->clock_count == -EINVAL) {
		sc->clock_count = 0;
	} else if (IS_ERR_VALUE(sc->clock_count)) {
		dev_err(&pdev->dev, "Failed to get clock names\n");
		return -EINVAL;
	}

	sc->clocks = devm_kzalloc(&pdev->dev,
			sizeof(struct clk *) * sc->clock_count, GFP_KERNEL);
	if (!sc->clocks)
		return -ENOMEM;

	sc->root_en = of_property_read_bool(pdev->dev.of_node,
						"qcom,enable-root-clk");

	for (i = 0; i < sc->clock_count; i++) {
		const char *clock_name;
		of_property_read_string_index(pdev->dev.of_node, "clock-names",
					      i, &clock_name);
		sc->clocks[i] = devm_clk_get(&pdev->dev, clock_name);
		if (IS_ERR(sc->clocks[i])) {
			int rc = PTR_ERR(sc->clocks[i]);
			if (rc != -EPROBE_DEFER)
				dev_err(&pdev->dev, "Failed to get %s\n",
					clock_name);
			return rc;
		}
	}

	sc->rdesc.id = atomic_inc_return(&gdsc_count);
	sc->rdesc.ops = &gdsc_ops;
	sc->rdesc.type = REGULATOR_VOLTAGE;
	sc->rdesc.owner = THIS_MODULE;
	platform_set_drvdata(pdev, sc);

	/*
	 * Disable HW trigger: collapse/restore occur based on registers writes.
	 * Disable SW override: Use hardware state-machine for sequencing.
	 */
	regval = readl_relaxed(sc->gdscr);
	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);

	/* Configure wait time between states. */
	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
	writel_relaxed(regval, sc->gdscr);

	retain_mem = of_property_read_bool(pdev->dev.of_node,
					    "qcom,retain-mem");
	sc->toggle_mem = !retain_mem;
	retain_periph = of_property_read_bool(pdev->dev.of_node,
					    "qcom,retain-periph");
	sc->toggle_periph = !retain_periph;
	sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
						"qcom,skip-logic-collapse");
	support_hw_trigger = of_property_read_bool(pdev->dev.of_node,
						    "qcom,support-hw-trigger");
	if (support_hw_trigger) {
		init_data->constraints.valid_ops_mask |= REGULATOR_CHANGE_MODE;
		init_data->constraints.valid_modes_mask |=
				REGULATOR_MODE_NORMAL | REGULATOR_MODE_FAST;
	}

	if (!sc->toggle_logic) {
		regval &= ~SW_COLLAPSE_MASK;
		writel_relaxed(regval, sc->gdscr);

		ret = readl_tight_poll_timeout(sc->gdscr, regval,
					regval & PWR_ON_MASK, TIMEOUT_US);
		if (ret) {
			dev_err(&pdev->dev, "%s enable timed out: 0x%x\n",
				sc->rdesc.name, regval);
			return ret;
		}
	}

	for (i = 0; i < sc->clock_count; i++) {
		if (retain_mem || (regval & PWR_ON_MASK))
			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
		else
			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);

		if (retain_periph || (regval & PWR_ON_MASK))
			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
		else
			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
	}

	reg_config.dev = &pdev->dev;
	reg_config.init_data = init_data;
	reg_config.driver_data = sc;
	reg_config.of_node = pdev->dev.of_node;
	sc->rdev = regulator_register(&sc->rdesc, &reg_config);
	if (IS_ERR(sc->rdev)) {
		dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n",
			sc->rdesc.name);
		return PTR_ERR(sc->rdev);
	}

	return 0;
}
Beispiel #22
0
/**
 * omap_device_build_from_dt - build an omap_device with multiple hwmods
 * @pdev_name: name of the platform_device driver to use
 * @pdev_id: this platform_device's connection ID
 * @oh: ptr to the single omap_hwmod that backs this omap_device
 * @pdata: platform_data ptr to associate with the platform_device
 * @pdata_len: amount of memory pointed to by @pdata
 *
 * Function for building an omap_device already registered from device-tree
 *
 * Returns 0 or PTR_ERR() on error.
 */
static int omap_device_build_from_dt(struct platform_device *pdev)
{
    struct omap_hwmod **hwmods;
    struct omap_device *od;
    struct omap_hwmod *oh;
    struct device_node *node = pdev->dev.of_node;
    const char *oh_name, *rst_name;
    int oh_cnt, dstr_cnt, i, ret = 0;
    bool device_active = false;

    oh_cnt = of_property_count_strings(node, "ti,hwmods");
    if (oh_cnt <= 0) {
        dev_dbg(&pdev->dev, "No 'hwmods' to build omap_device\n");
        return -ENODEV;
    }

    hwmods = kzalloc(sizeof(struct omap_hwmod *) * oh_cnt, GFP_KERNEL);
    if (!hwmods) {
        ret = -ENOMEM;
        goto odbfd_exit;
    }

    for (i = 0; i < oh_cnt; i++) {
        of_property_read_string_index(node, "ti,hwmods", i, &oh_name);
        oh = omap_hwmod_lookup(oh_name);
        if (!oh) {
            dev_err(&pdev->dev, "Cannot lookup hwmod '%s'\n",
                    oh_name);
            ret = -EINVAL;
            goto odbfd_exit1;
        }
        hwmods[i] = oh;
        if (oh->flags & HWMOD_INIT_NO_IDLE)
            device_active = true;
    }

    od = omap_device_alloc(pdev, hwmods, oh_cnt);
    if (IS_ERR(od)) {
        dev_err(&pdev->dev, "Cannot allocate omap_device for :%s\n",
                oh_name);
        ret = PTR_ERR(od);
        goto odbfd_exit1;
    }

    /* Fix up missing resource names */
    for (i = 0; i < pdev->num_resources; i++) {
        struct resource *r = &pdev->resource[i];

        if (r->name == NULL)
            r->name = dev_name(&pdev->dev);
    }

    pdev->dev.pm_domain = &omap_device_pm_domain;

    if (device_active) {
        omap_device_enable(pdev);
        pm_runtime_set_active(&pdev->dev);
    }
    dstr_cnt =
        of_property_count_strings(node, "ti,deassert-hard-reset");
    if (dstr_cnt > 0) {
        for (i = 0; i < dstr_cnt; i += 2) {
            of_property_read_string_index(
                node, "ti,deassert-hard-reset", i,
                &oh_name);
            of_property_read_string_index(
                node, "ti,deassert-hard-reset", i+1,
                &rst_name);
            oh = omap_hwmod_lookup(oh_name);
            if (!oh) {
                dev_warn(&pdev->dev,
                         "Cannot parse deassert property for '%s'\n",
                         oh_name);
                break;
            }
            omap_hwmod_deassert_hardreset(oh, rst_name);
        }
    }

odbfd_exit1:
    kfree(hwmods);
odbfd_exit:
    /* if data/we are at fault.. load up a fail handler */
    if (ret)
        pdev->dev.pm_domain = &omap_device_fail_pm_domain;

    return ret;
}
Beispiel #23
0
static int __init dra7xx_pcie_probe(struct platform_device *pdev)
{
	u32 reg;
	int ret;
	int irq;
	int i;
	int phy_count;
	struct phy **phy;
	void __iomem *base;
	struct resource *res;
	struct dra7xx_pcie *dra7xx;
	struct device *dev = &pdev->dev;
	struct device_node *np = dev->of_node;
	char name[10];
	int gpio_sel;
	enum of_gpio_flags flags;
	unsigned long gpio_flags;

	dra7xx = devm_kzalloc(dev, sizeof(*dra7xx), GFP_KERNEL);
	if (!dra7xx)
		return -ENOMEM;

	irq = platform_get_irq(pdev, 0);
	if (irq < 0) {
		dev_err(dev, "missing IRQ resource\n");
		return -EINVAL;
	}

	ret = devm_request_irq(dev, irq, dra7xx_pcie_irq_handler,
			       IRQF_SHARED, "dra7xx-pcie-main", dra7xx);
	if (ret) {
		dev_err(dev, "failed to request irq\n");
		return ret;
	}

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ti_conf");
	base = devm_ioremap_nocache(dev, res->start, resource_size(res));
	if (!base)
		return -ENOMEM;

	phy_count = of_property_count_strings(np, "phy-names");
	if (phy_count < 0) {
		dev_err(dev, "unable to find the strings\n");
		return phy_count;
	}

	phy = devm_kzalloc(dev, sizeof(*phy) * phy_count, GFP_KERNEL);
	if (!phy)
		return -ENOMEM;

	for (i = 0; i < phy_count; i++) {
		snprintf(name, sizeof(name), "pcie-phy%d", i);
		phy[i] = devm_phy_get(dev, name);
		if (IS_ERR(phy[i]))
			return PTR_ERR(phy[i]);

		ret = phy_init(phy[i]);
		if (ret < 0)
			goto err_phy;

		ret = phy_power_on(phy[i]);
		if (ret < 0) {
			phy_exit(phy[i]);
			goto err_phy;
		}
	}

	dra7xx->base = base;
	dra7xx->phy = phy;
	dra7xx->dev = dev;
	dra7xx->phy_count = phy_count;

	pm_runtime_enable(dev);
	ret = pm_runtime_get_sync(dev);
	if (ret < 0) {
		dev_err(dev, "pm_runtime_get_sync failed\n");
		goto err_get_sync;
	}

	gpio_sel = of_get_gpio_flags(dev->of_node, 0, &flags);
	if (gpio_is_valid(gpio_sel)) {
		gpio_flags = (flags & OF_GPIO_ACTIVE_LOW) ?
				GPIOF_OUT_INIT_LOW : GPIOF_OUT_INIT_HIGH;
		ret = devm_gpio_request_one(dev, gpio_sel, gpio_flags,
					    "pcie_reset");
		if (ret) {
			dev_err(&pdev->dev, "gpio%d request failed, ret %d\n",
				gpio_sel, ret);
			goto err_gpio;
		}
	} else if (gpio_sel == -EPROBE_DEFER) {
		ret = -EPROBE_DEFER;
		goto err_gpio;
	}

	reg = dra7xx_pcie_readl(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD);
	reg &= ~LTSSM_EN;
	dra7xx_pcie_writel(dra7xx, PCIECTRL_DRA7XX_CONF_DEVICE_CMD, reg);

	platform_set_drvdata(pdev, dra7xx);

	ret = dra7xx_add_pcie_port(dra7xx, pdev);
	if (ret < 0)
		goto err_gpio;

	return 0;

err_gpio:
	pm_runtime_put(dev);

err_get_sync:
	pm_runtime_disable(dev);

err_phy:
	while (--i >= 0) {
		phy_power_off(phy[i]);
		phy_exit(phy[i]);
	}

	return ret;
}
Beispiel #24
0
void __init opal_sys_param_init(void)
{
	struct device_node *sysparam;
	struct param_attr *attr;
	u32 *id, *size;
	int count, i;
	u8 *perm;

	if (!opal_kobj) {
		pr_warn("SYSPARAM: opal kobject is not available\n");
		goto out;
	}

	sysparam_kobj = kobject_create_and_add("sysparams", opal_kobj);
	if (!sysparam_kobj) {
		pr_err("SYSPARAM: Failed to create sysparam kobject\n");
		goto out;
	}

	/* Allocate big enough buffer for any get/set transactions */
	param_data_buf = kzalloc(MAX_PARAM_DATA_LEN, GFP_KERNEL);
	if (!param_data_buf) {
		pr_err("SYSPARAM: Failed to allocate memory for param data "
				"buf\n");
		goto out_kobj_put;
	}

	sysparam = of_find_node_by_path("/ibm,opal/sysparams");
	if (!sysparam) {
		pr_err("SYSPARAM: Opal sysparam node not found\n");
		goto out_param_buf;
	}

	if (!of_device_is_compatible(sysparam, "ibm,opal-sysparams")) {
		pr_err("SYSPARAM: Opal sysparam node not compatible\n");
		goto out_node_put;
	}

	/* Number of parameters exposed through DT */
	count = of_property_count_strings(sysparam, "param-name");
	if (count < 0) {
		pr_err("SYSPARAM: No string found of property param-name in "
				"the node %s\n", sysparam->name);
		goto out_node_put;
	}

	id = kzalloc(sizeof(*id) * count, GFP_KERNEL);
	if (!id) {
		pr_err("SYSPARAM: Failed to allocate memory to read parameter "
				"id\n");
		goto out_node_put;
	}

	size = kzalloc(sizeof(*size) * count, GFP_KERNEL);
	if (!size) {
		pr_err("SYSPARAM: Failed to allocate memory to read parameter "
				"size\n");
		goto out_free_id;
	}

	perm = kzalloc(sizeof(*perm) * count, GFP_KERNEL);
	if (!perm) {
		pr_err("SYSPARAM: Failed to allocate memory to read supported "
				"action on the parameter");
		goto out_free_size;
	}

	if (of_property_read_u32_array(sysparam, "param-id", id, count)) {
		pr_err("SYSPARAM: Missing property param-id in the DT\n");
		goto out_free_perm;
	}

	if (of_property_read_u32_array(sysparam, "param-len", size, count)) {
		pr_err("SYSPARAM: Missing propery param-len in the DT\n");
		goto out_free_perm;
	}


	if (of_property_read_u8_array(sysparam, "param-perm", perm, count)) {
		pr_err("SYSPARAM: Missing propery param-perm in the DT\n");
		goto out_free_perm;
	}

	attr = kzalloc(sizeof(*attr) * count, GFP_KERNEL);
	if (!attr) {
		pr_err("SYSPARAM: Failed to allocate memory for parameter "
				"attributes\n");
		goto out_free_perm;
	}

	/* For each of the parameters, populate the parameter attributes */
	for (i = 0; i < count; i++) {
		sysfs_attr_init(&attr[i].kobj_attr.attr);
		attr[i].param_id = id[i];
		attr[i].param_size = size[i];
		if (of_property_read_string_index(sysparam, "param-name", i,
				&attr[i].kobj_attr.attr.name))
			continue;

		/* If the parameter is read-only or read-write */
		switch (perm[i] & 3) {
		case OPAL_SYSPARAM_READ:
			attr[i].kobj_attr.attr.mode = S_IRUGO;
			break;
		case OPAL_SYSPARAM_WRITE:
			attr[i].kobj_attr.attr.mode = S_IWUGO;
			break;
		case OPAL_SYSPARAM_RW:
			attr[i].kobj_attr.attr.mode = S_IRUGO | S_IWUGO;
			break;
		default:
			break;
		}

		attr[i].kobj_attr.show = sys_param_show;
		attr[i].kobj_attr.store = sys_param_store;

		if (sysfs_create_file(sysparam_kobj, &attr[i].kobj_attr.attr)) {
			pr_err("SYSPARAM: Failed to create sysfs file %s\n",
					attr[i].kobj_attr.attr.name);
			goto out_free_attr;
		}
	}

	kfree(perm);
	kfree(size);
	kfree(id);
	of_node_put(sysparam);
	return;

out_free_attr:
	kfree(attr);
out_free_perm:
	kfree(perm);
out_free_size:
	kfree(size);
out_free_id:
	kfree(id);
out_node_put:
	of_node_put(sysparam);
out_param_buf:
	kfree(param_data_buf);
out_kobj_put:
	kobject_put(sysparam_kobj);
out:
	return;
}
int msm_camera_get_dt_power_setting_data(struct device_node *of_node,
	struct camera_vreg_t *cam_vreg, int num_vreg,
	struct msm_camera_power_ctrl_t *power_info)
{
	int rc = 0, i, j;
	int count = 0;
	const char *seq_name = NULL;
	uint32_t *array = NULL;
	struct msm_sensor_power_setting *ps;

	struct msm_sensor_power_setting *power_setting;
	uint16_t *power_setting_size, size = 0;
	bool need_reverse = 0;

	if (!power_info)
		return -EINVAL;

	power_setting = power_info->power_setting;
	power_setting_size = &power_info->power_setting_size;

	count = of_property_count_strings(of_node, "qcom,cam-power-seq-type");
	*power_setting_size = count;

	CDBG("%s qcom,cam-power-seq-type count %d\n", __func__, count);

	if (count <= 0)
		return 0;

	ps = kzalloc(sizeof(*ps) * count, GFP_KERNEL);
	if (!ps) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		return -ENOMEM;
	}
	power_setting = ps;
	power_info->power_setting = ps;

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node,
			"qcom,cam-power-seq-type", i,
			&seq_name);
		CDBG("%s seq_name[%d] = %s\n", __func__, i,
			seq_name);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			goto ERROR1;
		}
		if (!strcmp(seq_name, "sensor_vreg")) {
			ps[i].seq_type = SENSOR_VREG;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
		} else if (!strcmp(seq_name, "sensor_gpio")) {
			ps[i].seq_type = SENSOR_GPIO;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
		} else if (!strcmp(seq_name, "sensor_clk")) {
			ps[i].seq_type = SENSOR_CLK;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
		} else if (!strcmp(seq_name, "sensor_i2c_mux")) {
			ps[i].seq_type = SENSOR_I2C_MUX;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
		} else {
			CDBG("%s: unrecognized seq-type\n", __func__);
			rc = -EILSEQ;
			goto ERROR1;
		}
	}


	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node,
			"qcom,cam-power-seq-val", i,
			&seq_name);
		CDBG("%s seq_name[%d] = %s\n", __func__, i,
			seq_name);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			goto ERROR1;
		}
		switch (ps[i].seq_type) {
		case SENSOR_VREG:
			for (j = 0; j < num_vreg; j++) {
				if (!strcmp(seq_name, cam_vreg[j].reg_name))
					break;
			}
			if (j < num_vreg)
				ps[i].seq_val = j;
			else
				rc = -EILSEQ;
			break;
		case SENSOR_GPIO:
			if (!strcmp(seq_name, "sensor_gpio_reset"))
				ps[i].seq_val = SENSOR_GPIO_RESET;
			else if (!strcmp(seq_name, "sensor_gpio_standby"))
				ps[i].seq_val = SENSOR_GPIO_STANDBY;
			else if (!strcmp(seq_name, "sensor_gpio_vdig"))
				ps[i].seq_val = SENSOR_GPIO_VDIG;
			else
				rc = -EILSEQ;
			break;
		case SENSOR_CLK:
			if (!strcmp(seq_name, "sensor_cam_mclk"))
				ps[i].seq_val = SENSOR_CAM_MCLK;
			else if (!strcmp(seq_name, "sensor_cam_clk"))
				ps[i].seq_val = SENSOR_CAM_CLK;
			else
				rc = -EILSEQ;
			break;
		case SENSOR_I2C_MUX:
			if (!strcmp(seq_name, "none"))
				ps[i].seq_val = 0;
			else
				rc = -EILSEQ;
			break;
		default:
			rc = -EILSEQ;
			break;
		}
		if (rc < 0) {
			CDBG("%s: unrecognized seq-val\n", __func__);
			goto ERROR1;
		}
	}

	array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
	if (!array) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		rc = -ENOMEM;
		goto ERROR1;
	}


	rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-cfg-val",
		array, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	for (i = 0; i < count; i++) {
		if (ps[i].seq_type == SENSOR_GPIO) {
			if (array[i] == 0)
				ps[i].config_val = GPIO_OUT_LOW;
			else if (array[i] == 1)
				ps[i].config_val = GPIO_OUT_HIGH;
		} else {
			ps[i].config_val = array[i];
		}
		CDBG("%s power_setting[%d].config_val = %ld\n", __func__, i,
			ps[i].config_val);
	}

	rc = of_property_read_u32_array(of_node, "qcom,cam-power-seq-delay",
		array, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	for (i = 0; i < count; i++) {
		ps[i].delay = array[i];
		CDBG("%s power_setting[%d].delay = %d\n", __func__,
			i, ps[i].delay);
	}
	kfree(array);

	size = *power_setting_size;

	if (NULL != ps && 0 != size)
		need_reverse = 1;

	power_info->power_down_setting =
		kzalloc(sizeof(*ps) * size, GFP_KERNEL);

	if (!power_info->power_down_setting) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		rc = -ENOMEM;
		goto ERROR1;
	}

	memcpy(power_info->power_down_setting,
		ps, sizeof(*ps) * size);

	power_info->power_down_setting_size = size;

	if (need_reverse) {
		int c, end = size - 1;
		struct msm_sensor_power_setting power_down_setting_t;
		for (c = 0; c < size/2; c++) {
			power_down_setting_t =
				power_info->power_down_setting[c];
			power_info->power_down_setting[c] =
				power_info->power_down_setting[end];
			power_info->power_down_setting[end] =
				power_down_setting_t;
			end--;
		}
	}
	return rc;
ERROR2:
	kfree(array);
ERROR1:
	kfree(ps);
	power_setting_size = 0;
	return rc;
}
/*
 * This function reads the following from dtsi file
 * 1. All gpio sets
 * 2. All combinations of gpio sets
 * 3. Pinctrl handles to gpio sets
 *
 * Returns error if there is
 * 1. Problem reading from dtsi file
 * 2. Memory allocation failure
 */
int msm_gpioset_initialize(enum pinctrl_client client,
				struct device *dev)
{
	struct pinctrl *pinctrl;
	const char *gpioset_names = "qcom,msm-gpios";
	const char *gpioset_combinations = "qcom,pinctrl-names";
	const char *gpioset_names_str = NULL;
	const char *gpioset_comb_str = NULL;
	int num_strings = 0;
	int ret = 0;
	int i = 0;

	pr_debug("%s\n", __func__);
	pinctrl = devm_pinctrl_get(dev);
	if (IS_ERR(pinctrl)) {
		pr_err("%s: Unable to get pinctrl handle\n",
				__func__);
		return -EINVAL;
	}
	pinctrl_info[client].pinctrl = pinctrl;

	/* Reading of gpio sets */
	num_strings = of_property_count_strings(dev->of_node,
						gpioset_names);
	if (num_strings < 0) {
		dev_err(dev,
			"%s: missing %s in dt node or length is incorrect\n",
				__func__, gpioset_names);
		goto err;
	}
	gpioset_info[client].gpiosets_max = num_strings;
	gpioset_info[client].gpiosets = devm_kzalloc(dev,
				gpioset_info[client].gpiosets_max *
					sizeof(char *), GFP_KERNEL);
	if (!gpioset_info[client].gpiosets) {
		dev_err(dev, "Can't allocate memory for gpio set names\n");
		ret = -ENOMEM;
		goto err;
	}

	for (i = 0; i < num_strings; i++) {
		ret = of_property_read_string_index(dev->of_node,
					gpioset_names, i, &gpioset_names_str);

		gpioset_info[client].gpiosets[i] = devm_kzalloc(dev,
				(strlen(gpioset_names_str) + 1), GFP_KERNEL);

		if (!gpioset_info[client].gpiosets[i]) {
			dev_err(dev, "%s: Can't allocate gpiosets[%d] data\n",
						__func__, i);
			ret = -ENOMEM;
			goto err;
		}
		strlcpy(gpioset_info[client].gpiosets[i],
				gpioset_names_str, strlen(gpioset_names_str)+1);
		gpioset_names_str = NULL;
	}
	num_strings = 0;

	/* Allocating memory for gpio set counter */
	gpioset_info[client].gpioset_state = devm_kzalloc(dev,
				gpioset_info[client].gpiosets_max *
				sizeof(uint8_t), GFP_KERNEL);
	if (!gpioset_info[client].gpioset_state) {
		dev_err(dev, "Can't allocate memory for gpio set counter\n");
		ret = -ENOMEM;
		goto err;
	}

	/* Reading of all combinations of gpio sets */
	num_strings = of_property_count_strings(dev->of_node,
						gpioset_combinations);
	if (num_strings < 0) {
		dev_err(dev,
			"%s: missing %s in dt node or length is incorrect\n",
			__func__, gpioset_combinations);
		goto err;
	}
	gpioset_info[client].gpiosets_comb_max = num_strings;
	gpioset_info[client].gpiosets_comb_names = devm_kzalloc(dev,
				num_strings * sizeof(char *), GFP_KERNEL);
	if (!gpioset_info[client].gpiosets_comb_names) {
		dev_err(dev, "Can't allocate gpio set combination names data\n");
		ret = -ENOMEM;
		goto err;
	}

	for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) {
		ret = of_property_read_string_index(dev->of_node,
				gpioset_combinations, i, &gpioset_comb_str);

		gpioset_info[client].gpiosets_comb_names[i] = devm_kzalloc(dev,
				(strlen(gpioset_comb_str) + 1), GFP_KERNEL);
		if (!gpioset_info[client].gpiosets_comb_names[i]) {
			dev_err(dev, "%s: Can't allocate combinations[%d] data\n",
					__func__, i);
			ret = -ENOMEM;
			goto err;
		}

		strlcpy(gpioset_info[client].gpiosets_comb_names[i],
					gpioset_comb_str,
					strlen(gpioset_comb_str)+1);
		pr_debug("%s: GPIO configuration %s\n",
				__func__,
				gpioset_info[client].gpiosets_comb_names[i]);
		gpioset_comb_str = NULL;
	}

	/* Allocating memory for handles to pinctrl states */
	pinctrl_info[client].cdc_lines = devm_kzalloc(dev,
		num_strings * sizeof(char *), GFP_KERNEL);
	if (!pinctrl_info[client].cdc_lines) {
		dev_err(dev, "Can't allocate pinctrl_info.cdc_lines data\n");
		ret = -ENOMEM;
		goto err;
	}

	/* Get pinctrl handles for gpio sets in dtsi file */
	for (i = 0; i < num_strings; i++) {
		pinctrl_info[client].cdc_lines[i] = pinctrl_lookup_state(
								pinctrl,
					(const char *)gpioset_info[client].
							gpiosets_comb_names[i]);
		if (IS_ERR(pinctrl_info[client].cdc_lines[i]))
			pr_err("%s: Unable to get pinctrl handle for %s\n",
				__func__, gpioset_info[client].
						gpiosets_comb_names[i]);
	}
	goto success;

err:
	/* Free up memory allocated for gpio set combinations */
	for (i = 0; i < gpioset_info[client].gpiosets_max; i++) {
		if (NULL != gpioset_info[client].gpiosets[i])
			devm_kfree(dev, gpioset_info[client].gpiosets[i]);
	}
	if (NULL != gpioset_info[client].gpiosets)
		devm_kfree(dev, gpioset_info[client].gpiosets);

	/* Free up memory allocated for gpio set combinations */
	for (i = 0; i < gpioset_info[client].gpiosets_comb_max; i++) {
		if (NULL != gpioset_info[client].gpiosets_comb_names[i])
			devm_kfree(dev,
			gpioset_info[client].gpiosets_comb_names[i]);
	}
	if (NULL != gpioset_info[client].gpiosets_comb_names)
		devm_kfree(dev, gpioset_info[client].gpiosets_comb_names);

	/* Free up memory allocated for handles to pinctrl states */
	if (NULL != pinctrl_info[client].cdc_lines)
		devm_kfree(dev, pinctrl_info[client].cdc_lines);

	/* Free up memory allocated for counter of gpio sets */
	if (NULL != gpioset_info[client].gpioset_state)
		devm_kfree(dev, gpioset_info[client].gpioset_state);

success:
	return ret;
}
static int __devinit gdsc_probe(struct platform_device *pdev)
{
	static atomic_t gdsc_count = ATOMIC_INIT(-1);
	struct regulator_init_data *init_data;
	struct resource *res;
	struct gdsc *sc;
	uint32_t regval;
	bool retain_mem, retain_periph;
	int i, ret;
#ifdef CONFIG_MACH_LGE
	int use_lge_workaround = 0; /* default: all not applied */
#endif

	sc = devm_kzalloc(&pdev->dev, sizeof(struct gdsc), GFP_KERNEL);
	if (sc == NULL)
		return -ENOMEM;

	init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
	if (init_data == NULL)
		return -ENOMEM;

	if (of_get_property(pdev->dev.of_node, "parent-supply", NULL))
		init_data->supply_regulator = "parent";

	ret = of_property_read_string(pdev->dev.of_node, "regulator-name",
				      &sc->rdesc.name);
	if (ret)
		return ret;

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (res == NULL)
		return -EINVAL;
	sc->gdscr = devm_ioremap(&pdev->dev, res->start, resource_size(res));
	if (sc->gdscr == NULL)
		return -ENOMEM;

	sc->clock_count = of_property_count_strings(pdev->dev.of_node,
					    "qcom,clock-names");
	if (sc->clock_count == -EINVAL) {
		sc->clock_count = 0;
	} else if (IS_ERR_VALUE(sc->clock_count)) {
		dev_err(&pdev->dev, "Failed to get clock names\n");
		return -EINVAL;
	}

	sc->clocks = devm_kzalloc(&pdev->dev,
			sizeof(struct clk *) * sc->clock_count, GFP_KERNEL);
	if (!sc->clocks)
		return -ENOMEM;
	for (i = 0; i < sc->clock_count; i++) {
		const char *clock_name;
		of_property_read_string_index(pdev->dev.of_node,
					      "qcom,clock-names", i,
					      &clock_name);
		sc->clocks[i] = devm_clk_get(&pdev->dev, clock_name);
		if (IS_ERR(sc->clocks[i])) {
			int rc = PTR_ERR(sc->clocks[i]);
			if (rc != -EPROBE_DEFER)
				dev_err(&pdev->dev, "Failed to get %s\n",
					clock_name);
			return rc;
		}
	}
#ifdef CONFIG_MACH_LGE
	of_property_read_u32(pdev->dev.of_node, "lge,use_workaround",
			&use_lge_workaround);
	sc->use_lge_workaround = !(!use_lge_workaround);
#endif
	sc->rdesc.id = atomic_inc_return(&gdsc_count);
	sc->rdesc.ops = &gdsc_ops;
	sc->rdesc.type = REGULATOR_VOLTAGE;
	sc->rdesc.owner = THIS_MODULE;
	platform_set_drvdata(pdev, sc);

	/*
	 * Disable HW trigger: collapse/restore occur based on registers writes.
	 * Disable SW override: Use hardware state-machine for sequencing.
	 */
	regval = readl_relaxed(sc->gdscr);
	regval &= ~(HW_CONTROL_MASK | SW_OVERRIDE_MASK);

	/* Configure wait time between states. */
	regval &= ~(EN_REST_WAIT_MASK | EN_FEW_WAIT_MASK | CLK_DIS_WAIT_MASK);
	regval |= EN_REST_WAIT_VAL | EN_FEW_WAIT_VAL | CLK_DIS_WAIT_VAL;
	writel_relaxed(regval, sc->gdscr);

	retain_mem = of_property_read_bool(pdev->dev.of_node,
					    "qcom,retain-mem");
	retain_periph = of_property_read_bool(pdev->dev.of_node,
					    "qcom,retain-periph");
	for (i = 0; i < sc->clock_count; i++) {
		if (retain_mem || (regval & PWR_ON_MASK))
			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_MEM);
		else
			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_MEM);

		if (retain_periph || (regval & PWR_ON_MASK))
			clk_set_flags(sc->clocks[i], CLKFLAG_RETAIN_PERIPH);
		else
			clk_set_flags(sc->clocks[i], CLKFLAG_NORETAIN_PERIPH);
	}
	sc->toggle_mem = !retain_mem;
	sc->toggle_periph = !retain_periph;
	sc->toggle_logic = !of_property_read_bool(pdev->dev.of_node,
						"qcom,skip-logic-collapse");
	if (!sc->toggle_logic) {
#ifdef CONFIG_MACH_LGE
		/* LGE workaround is not used if a device is good pdn revision */
		if (lge_get_board_revno() >= use_lge_workaround) {
			regval &= ~SW_COLLAPSE_MASK;
			writel_relaxed(regval, sc->gdscr);

			ret = readl_tight_poll_timeout(sc->gdscr, regval,
					regval & PWR_ON_MASK, TIMEOUT_US);
			if (ret) {
				dev_err(&pdev->dev, "%s enable timed out\n",
						sc->rdesc.name);
				return ret;
			}
		} else {
			pr_info("%s: %s is enabled only at first by lge workaround\n",
					__func__, sc->rdesc.name);
			ret = lge_gdsc_enable(sc);
			if (ret) {
				dev_err(&pdev->dev, "%s enable timed out\n",
						sc->rdesc.name);
				return ret;
			}
		}
#else /* qmc */
		regval &= ~SW_COLLAPSE_MASK;
		writel_relaxed(regval, sc->gdscr);

		ret = readl_tight_poll_timeout(sc->gdscr, regval,
					regval & PWR_ON_MASK, TIMEOUT_US);
		if (ret) {
			dev_err(&pdev->dev, "%s enable timed out\n",
				sc->rdesc.name);
			return ret;
		}
#endif
	}

	sc->rdev = regulator_register(&sc->rdesc, &pdev->dev, init_data, sc,
				      pdev->dev.of_node);
	if (IS_ERR(sc->rdev)) {
		dev_err(&pdev->dev, "regulator_register(\"%s\") failed.\n",
			sc->rdesc.name);
		return PTR_ERR(sc->rdev);
	}

	return 0;
}
static int power_sysfs_parse_dt(struct platform_device *pdev)
{
	struct device_node *node = pdev->dev.of_node;
	int arr_num, ret, i;

	arr_cnt = of_property_count_strings(node, "sysfs,node") / 3;
	if (arr_cnt > 0)
		pr_info("%s : Total sysfs node is %d\n", __func__, arr_cnt);
	else {
		pr_err("%s : ERROR sysfs node isn't exist\n", __func__);
		return 0;
	}

	arr = kzalloc(arr_cnt * sizeof(struct power_sysfs_array),
			GFP_KERNEL);
	if (arr != NULL) {
		for (arr_num = 0, i = 0; arr_num < arr_cnt; arr_num++) {
			ret = of_property_read_string_index(node, "sysfs,node",
					i++, &arr[arr_num].group);
			if (ret) {
				pr_err("%s : ERROR get %ith group\n", __func__, arr_num);
				goto err_get_array;
			}
			ret = of_property_read_string_index(node, "sysfs,node",
					i++, &arr[arr_num].user_node);
			if (ret) {
				pr_err("%s : ERROR get %ith user_node\n", __func__, arr_num);
				goto err_get_array;
			}
			ret = of_property_read_string_index(node, "sysfs,node",
					i++, &arr[arr_num].kernel_node);
			if (ret) {
				pr_err("%s : ERROR get %ith kernel_node\n", __func__, arr_num);
				goto err_get_array;
			} else if (check_mandatory_path(arr_num)) {
				if (!strcmp(arr[arr_num].kernel_node, "NULL")) {
					pr_err("%s : ERROR get mandatory path %s\n", __func__,
							arr[arr_num].user_node);
					goto err_get_array;
				}
				pr_info("%s : %s path is mandatory \n", __func__,
						arr[arr_num].user_node);
			}
		}
	} else {
		pr_err("%s : ERROR get sysfs array\n", __func__);
		return -1;
	}
/* debug */
	for (arr_num = 0; arr_num < arr_cnt; arr_num++)
		pr_err("%s : get %dth node is %s, %s, %s\n", __func__, arr_num,
				arr[arr_num].group, arr[arr_num].user_node,
				arr[arr_num].kernel_node);

	return 0;

err_get_array:
	kzfree(arr);

	return -1;
}
int msm_camera_get_dt_vreg_data(struct device_node *of_node,
	struct camera_vreg_t **cam_vreg, int *num_vreg)
{
	int rc = 0, i = 0;
	uint32_t count = 0;
	uint32_t *vreg_array = NULL;
	struct camera_vreg_t *vreg = NULL;

	count = of_property_count_strings(of_node, "qcom,cam-vreg-name");
	CDBG("%s qcom,cam-vreg-name count %d\n", __func__, count);

	if (!count)
		return 0;

	vreg = kzalloc(sizeof(*vreg) * count, GFP_KERNEL);
	if (!vreg) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		return -ENOMEM;
	}
	*cam_vreg = vreg;
	*num_vreg = count;
	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node,
			"qcom,cam-vreg-name", i,
			&vreg[i].reg_name);
		CDBG("%s reg_name[%d] = %s\n", __func__, i,
			vreg[i].reg_name);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			goto ERROR1;
		}
	}

	vreg_array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
	if (!vreg_array) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		rc = -ENOMEM;
		goto ERROR1;
	}

	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-type",
		vreg_array, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	for (i = 0; i < count; i++) {
		vreg[i].type = vreg_array[i];
		CDBG("%s cam_vreg[%d].type = %d\n", __func__, i,
			vreg[i].type);
	}

	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-min-voltage",
		vreg_array, count);
	if (rc == 0) {
		for (i = 0; i < count; i++) {
			vreg[i].min_voltage = vreg_array[i];
			CDBG("%s cam_vreg[%d].min_voltage = %d\n", __func__,
				i, vreg[i].min_voltage);
	}
	}

	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-max-voltage",
		vreg_array, count);
	if (rc == 0) {
		for (i = 0; i < count; i++) {
			vreg[i].max_voltage = vreg_array[i];
			CDBG("%s cam_vreg[%d].max_voltage = %d\n", __func__,
				i, vreg[i].max_voltage);
	}
	}

	rc = of_property_read_u32_array(of_node, "qcom,cam-vreg-op-mode",
		vreg_array, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	for (i = 0; i < count; i++) {
		vreg[i].op_mode = vreg_array[i];
		CDBG("%s cam_vreg[%d].op_mode = %d\n", __func__, i,
			vreg[i].op_mode);
	}

	kfree(vreg_array);
	return rc;
ERROR2:
	kfree(vreg_array);
ERROR1:
	kfree(vreg);
	*num_vreg = 0;
	return rc;
}
int msm_camera_get_dt_power_off_setting_data(struct device_node *of_node,
	struct camera_vreg_t *cam_vreg, int num_vreg,
	struct msm_sensor_power_setting **power_setting,
	uint16_t *power_setting_size)
{
	int rc = 0, i, j;
	int count = 0;
	const char *seq_name = NULL;
	uint32_t *array = NULL;
	struct msm_sensor_power_setting *ps;

	if (!power_setting || !power_setting_size)
		return -EINVAL;

	count = of_property_count_strings(of_node, "qcom,cam-power-off-seq-type");
	*power_setting_size = count;
	CDBG("%s qcom,cam-power-off-seq-type count %d\n", __func__, count);

	if (count <= 0)
		return 0;

	ps = kzalloc(sizeof(*ps) * count, GFP_KERNEL);
	if (!ps) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		return -ENOMEM;
	}
	*power_setting = ps;

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node,
			"qcom,cam-power-off-seq-type", i,
			&seq_name);
		CDBG("%s seq_name[%d] = %s\n", __func__, i,
			seq_name);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			goto ERROR1;
		}
		if (!strcmp(seq_name, "sensor_vreg")) {
			ps[i].seq_type = SENSOR_VREG;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
		} else if (!strcmp(seq_name, "sensor_gpio")) {
			ps[i].seq_type = SENSOR_GPIO;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
		} else if (!strcmp(seq_name, "sensor_clk")) {
			ps[i].seq_type = SENSOR_CLK;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
		} else if (!strcmp(seq_name, "sensor_i2c_mux")) {
			ps[i].seq_type = SENSOR_I2C_MUX;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
#if defined(CONFIG_MACH_MONTBLANC) || defined(CONFIG_MACH_VIKALCU)
		} else if (!strcmp(seq_name, "sensor_additional_ldo")) {
			ps[i].seq_type = SENSOR_ADDITIONAL_LDO;
			CDBG("%s:%d seq_type[%d] %d\n", __func__, __LINE__,
				i, ps[i].seq_type);
#endif
		} else {
			CDBG("%s: unrecognized seq-type\n", __func__);
			rc = -EILSEQ;
			goto ERROR1;
		}
	}


	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node,
			"qcom,cam-power-off-seq-val", i,
			&seq_name);
		CDBG("%s seq_name[%d] = %s\n", __func__, i,
			seq_name);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			goto ERROR1;
		}
		switch (ps[i].seq_type) {
		case SENSOR_VREG:
			for (j = 0; j < num_vreg; j++) {
				if (!strcmp(seq_name, cam_vreg[j].reg_name))
					break;
			}
			if (j < num_vreg)
				ps[i].seq_val = j;
			else
				rc = -EILSEQ;
			break;
#if defined(CONFIG_MACH_MONTBLANC)
		case SENSOR_ADDITIONAL_LDO:
#endif
		case SENSOR_GPIO:
			if (!strcmp(seq_name, "sensor_gpio_reset"))
				ps[i].seq_val = SENSOR_GPIO_RESET;
			else if (!strcmp(seq_name, "sensor_gpio_standby"))
				ps[i].seq_val = SENSOR_GPIO_STANDBY;
			else if (!strcmp(seq_name, "sensor_gpio_ext_vana_power"))
				ps[i].seq_val = SENSOR_GPIO_EXT_VANA_POWER;
			else if (!strcmp(seq_name, "sensor_gpio_ext_vio_power"))
				ps[i].seq_val = SENSOR_GPIO_EXT_VIO_POWER;
			else if (!strcmp(seq_name, "sensor_gpio_ext_vcore_power"))
				ps[i].seq_val = SENSOR_GPIO_EXT_VCORE_POWER;
			else
				rc = -EILSEQ;
			break;
		case SENSOR_CLK:
			if (!strcmp(seq_name, "sensor_cam_mclk"))
			ps[i].seq_val = SENSOR_CAM_MCLK;
		else if (!strcmp(seq_name, "sensor_cam_clk"))
			ps[i].seq_val = SENSOR_CAM_CLK;
			else
				rc = -EILSEQ;
			break;
		case SENSOR_I2C_MUX:
			if (!strcmp(seq_name, "none"))
			ps[i].seq_val = 0;
			else
				rc = -EILSEQ;
			break;
		default:
			rc = -EILSEQ;
			break;
		}
		if (rc < 0) {
			CDBG("%s: unrecognized seq-val\n", __func__);
			goto ERROR1;
		}
	}

	array = kzalloc(sizeof(uint32_t) * count, GFP_KERNEL);
	if (!array) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		rc = -ENOMEM;
		goto ERROR1;
	}


	rc = of_property_read_u32_array(of_node, "qcom,cam-power-off-seq-cfg-val",
		array, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	for (i = 0; i < count; i++) {
		if (ps[i].seq_type == SENSOR_GPIO) {
			if (array[i] == 0)
				ps[i].config_val = GPIO_OUT_LOW;
			else if (array[i] == 1)
				ps[i].config_val = GPIO_OUT_HIGH;
		} else {
			ps[i].config_val = array[i];
		}
		CDBG("%s power_setting[%d].config_val = %ld\n", __func__, i,
			ps[i].config_val);
	}

	rc = of_property_read_u32_array(of_node, "qcom,cam-power-off-seq-delay",
		array, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	for (i = 0; i < count; i++) {
		ps[i].delay = array[i];
		CDBG("%s power_setting[%d].delay = %d\n", __func__,
			i, ps[i].delay);
	}
	kfree(array);
	return rc;
ERROR2:
	kfree(array);
ERROR1:
	kfree(ps);
	power_setting_size = 0;
	return rc;
}