Esempio n. 1
10
static void __init cpg_mstp_clocks_init(struct device_node *np)
{
	struct mstp_clock_group *group;
	const char *idxname;
	struct clk **clks;
	unsigned int i;

	group = kzalloc(sizeof(*group), GFP_KERNEL);
	clks = kmalloc(MSTP_MAX_CLOCKS * sizeof(*clks), GFP_KERNEL);
	if (group == NULL || clks == NULL) {
		kfree(group);
		kfree(clks);
		pr_err("%s: failed to allocate group\n", __func__);
		return;
	}

	spin_lock_init(&group->lock);
	group->data.clks = clks;

	group->smstpcr = of_iomap(np, 0);
	group->mstpsr = of_iomap(np, 1);

	if (group->smstpcr == NULL) {
		pr_err("%s: failed to remap SMSTPCR\n", __func__);
		kfree(group);
		kfree(clks);
		return;
	}

	for (i = 0; i < MSTP_MAX_CLOCKS; ++i)
		clks[i] = ERR_PTR(-ENOENT);

	if (of_find_property(np, "clock-indices", &i))
		idxname = "clock-indices";
	else
		idxname = "renesas,clock-indices";

	for (i = 0; i < MSTP_MAX_CLOCKS; ++i) {
		const char *parent_name;
		const char *name;
		u32 clkidx;
		int ret;

		/* Skip clocks with no name. */
		ret = of_property_read_string_index(np, "clock-output-names",
						    i, &name);
		if (ret < 0 || strlen(name) == 0)
			continue;

		parent_name = of_clk_get_parent_name(np, i);
		ret = of_property_read_u32_index(np, idxname, i, &clkidx);
		if (parent_name == NULL || ret < 0)
			break;

		if (clkidx >= MSTP_MAX_CLOCKS) {
			pr_err("%s: invalid clock %s %s index %u)\n",
			       __func__, np->name, name, clkidx);
			continue;
		}

		clks[clkidx] = cpg_mstp_clock_register(name, parent_name,
						       clkidx, group);
		if (!IS_ERR(clks[clkidx])) {
			group->data.clk_num = max(group->data.clk_num,
						  clkidx + 1);
			/*
			 * Register a clkdev to let board code retrieve the
			 * clock by name and register aliases for non-DT
			 * devices.
			 *
			 * FIXME: Remove this when all devices that require a
			 * clock will be instantiated from DT.
			 */
			clk_register_clkdev(clks[clkidx], name, NULL);
		} else {
			pr_err("%s: failed to register %s %s clock (%ld)\n",
			       __func__, np->name, name, PTR_ERR(clks[clkidx]));
		}
	}

	of_clk_add_provider(np, of_clk_src_onecell_get, &group->data);
}
Esempio n. 2
0
static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
{
	struct device_node *dn = pdev->dev.of_node;
	struct brcmstb_gisb_arb_device *gdev;
	const struct of_device_id *of_id;
	struct resource *r;
	int err, timeout_irq, tea_irq;
	unsigned int num_masters, j = 0;
	int i, first, last;

	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	timeout_irq = platform_get_irq(pdev, 0);
	tea_irq = platform_get_irq(pdev, 1);

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

	mutex_init(&gdev->lock);
	INIT_LIST_HEAD(&gdev->next);

	gdev->base = devm_ioremap_resource(&pdev->dev, r);
	if (IS_ERR(gdev->base))
		return PTR_ERR(gdev->base);

	of_id = of_match_node(brcmstb_gisb_arb_of_match, dn);
	if (!of_id) {
		pr_err("failed to look up compatible string\n");
		return -EINVAL;
	}
	gdev->gisb_offsets = of_id->data;
	gdev->big_endian = of_device_is_big_endian(dn);

	err = devm_request_irq(&pdev->dev, timeout_irq,
				brcmstb_gisb_timeout_handler, 0, pdev->name,
				gdev);
	if (err < 0)
		return err;

	err = devm_request_irq(&pdev->dev, tea_irq,
				brcmstb_gisb_tea_handler, 0, pdev->name,
				gdev);
	if (err < 0)
		return err;

	/* If we do not have a valid mask, assume all masters are enabled */
	if (of_property_read_u32(dn, "brcm,gisb-arb-master-mask",
				&gdev->valid_mask))
		gdev->valid_mask = 0xffffffff;

	/* Proceed with reading the litteral names if we agree on the
	 * number of masters
	 */
	num_masters = of_property_count_strings(dn,
			"brcm,gisb-arb-master-names");
	if (hweight_long(gdev->valid_mask) == num_masters) {
		first = ffs(gdev->valid_mask) - 1;
		last = fls(gdev->valid_mask) - 1;

		for (i = first; i < last; i++) {
			if (!(gdev->valid_mask & BIT(i)))
				continue;

			of_property_read_string_index(dn,
					"brcm,gisb-arb-master-names", j,
					&gdev->master_names[i]);
			j++;
		}
	}

	err = sysfs_create_group(&pdev->dev.kobj, &gisb_arb_sysfs_attr_group);
	if (err)
		return err;

	platform_set_drvdata(pdev, gdev);

	list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list);

#ifdef CONFIG_ARM
	hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0,
			"imprecise external abort");
#endif

	dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
			gdev->base, timeout_irq, tea_irq);

	return 0;
}
static void of_gpiochip_add_pin_range(struct gpio_chip *chip)
{
	struct device_node *np = chip->of_node;
	struct of_phandle_args pinspec;
	struct pinctrl_dev *pctldev;
	int index = 0, ret;
	const char *name;
	static const char group_names_propname[] = "gpio-ranges-group-names";
	struct property *group_names;

	if (!np)
		return;

	group_names = of_find_property(np, group_names_propname, NULL);

	for (;; index++) {
		ret = of_parse_phandle_with_fixed_args(np, "gpio-ranges", 3,
				index, &pinspec);
		if (ret)
			break;

		pctldev = of_pinctrl_get(pinspec.np);
		if (!pctldev)
			break;

		if (pinspec.args[2]) {
			if (group_names) {
				ret = of_property_read_string_index(np,
						group_names_propname,
						index, &name);
				if (strlen(name)) {
					pr_err("%s: Group name of numeric GPIO ranges must be the empty string.\n",
						np->full_name);
					break;
				}
			}
			/* npins != 0: linear range */
			ret = gpiochip_add_pin_range(chip,
					pinctrl_dev_get_devname(pctldev),
					pinspec.args[0],
					pinspec.args[1],
					pinspec.args[2]);
			if (ret)
				break;
		} else {
			/* npins == 0: special range */
			if (pinspec.args[1]) {
				pr_err("%s: Illegal gpio-range format.\n",
					np->full_name);
				break;
			}

			if (!group_names) {
				pr_err("%s: GPIO group range requested but no %s property.\n",
					np->full_name, group_names_propname);
				break;
			}

			ret = of_property_read_string_index(np,
						group_names_propname,
						index, &name);
			if (ret)
				break;

			if (!strlen(name)) {
				pr_err("%s: Group name of GPIO group range cannot be the empty string.\n",
				np->full_name);
				break;
			}

			ret = gpiochip_add_pingroup_range(chip, pctldev,
						pinspec.args[0], name);
			if (ret)
				break;
		}
	}
}
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) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	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) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	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_gpio_req_tbl(struct device_node *of_node,
	struct msm_camera_gpio_conf *gconf, uint16_t *gpio_array,
	uint16_t gpio_array_size)
{
	int rc = 0, i = 0;
	uint32_t count = 0;
	uint32_t *val_array = NULL;

	if (!of_get_property(of_node, "qcom,gpio-req-tbl-num", &count))
		return 0;

	count /= sizeof(uint32_t);
	if (!count) {
		pr_err("%s qcom,gpio-req-tbl-num 0\n", __func__);
		return 0;
	}

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

	gconf->cam_gpio_req_tbl = kzalloc(sizeof(struct gpio) * count,
		GFP_KERNEL);
	if (!gconf->cam_gpio_req_tbl) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		rc = -ENOMEM;
		goto ERROR1;
	}
	gconf->cam_gpio_req_tbl_size = count;

	rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-num",
		val_array, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	for (i = 0; i < count; i++) {
		if (val_array[i] >= gpio_array_size) {
			pr_err("%s gpio req tbl index %d invalid\n",
				__func__, val_array[i]);
			return -EINVAL;
		}
		gconf->cam_gpio_req_tbl[i].gpio = gpio_array[val_array[i]];
		CDBG("%s cam_gpio_req_tbl[%d].gpio = %d\n", __func__, i,
			gconf->cam_gpio_req_tbl[i].gpio);
	}

	rc = of_property_read_u32_array(of_node, "qcom,gpio-req-tbl-flags",
		val_array, count);
	if (rc < 0) {
		pr_err("%s failed %d\n", __func__, __LINE__);
		goto ERROR2;
	}
	for (i = 0; i < count; i++) {
		gconf->cam_gpio_req_tbl[i].flags = val_array[i];
		CDBG("%s cam_gpio_req_tbl[%d].flags = %ld\n", __func__, i,
			gconf->cam_gpio_req_tbl[i].flags);
	}

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node,
			"qcom,gpio-req-tbl-label", i,
			&gconf->cam_gpio_req_tbl[i].label);
		CDBG("%s cam_gpio_req_tbl[%d].label = %s\n", __func__, i,
			gconf->cam_gpio_req_tbl[i].label);
		if (rc < 0) {
			pr_err("%s failed %d\n", __func__, __LINE__);
			goto ERROR2;
		}
	}

	kfree(val_array);
	return rc;

ERROR2:
	kfree(gconf->cam_gpio_req_tbl);
ERROR1:
	kfree(val_array);
	gconf->cam_gpio_req_tbl_size = 0;
	return rc;
}
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 if (!strcmp(seq_name, "sensor_gpio_vio"))
				ps[i].seq_val = SENSOR_GPIO_VIO;
			else if (!strcmp(seq_name, "sensor_gpio_vana"))
				ps[i].seq_val = SENSOR_GPIO_VANA;
			else if (!strcmp(seq_name, "sensor_gpio_vaf"))
				ps[i].seq_val = SENSOR_GPIO_VAF;
			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;
}
int msm_ispif_get_clk_info(struct ispif_device *ispif_dev,
	struct platform_device *pdev,
	struct msm_cam_clk_info *ahb_clk_info,
	struct msm_cam_clk_info *clk_info)
{
	uint32_t count, num_ahb_clk = 0;
	const char *rate = NULL;
	int i, rc;

	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;
	}

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node, "clock-names",
				i, &(clk_info[i].clk_name));
		if (rc < 0) {
			pr_err("%s reading clock-name failed index %d\n",
				__func__, i);
			return rc;
		}

		rc = of_property_read_string_index(of_node, "qcom,clock-rates",
			i, &rate);
		CDBG("clock-names[%d] = %s, clk_rate = %s\n",
			i, clk_info[i].clk_name, rate);
		if (rc < 0) {
			pr_err("%s reading clock-rate failed index %d\n",
				__func__, i);
			return rc;
		}

		if (!strcmp(rate, "-1") || !strcmp(rate, "0"))
			clk_info[i].clk_rate = NO_SET_RATE;
		else if (!strcmp(rate, "-2"))
			clk_info[i].clk_rate = INIT_RATE;
		else
			rc = kstrtol(rate, 10, &clk_info[i].clk_rate);

		if (strnstr(clk_info[i].clk_name, "ahb",
			strlen(clk_info[i].clk_name))) {
			ahb_clk_info[num_ahb_clk].clk_name =
				clk_info[i].clk_name;
			ahb_clk_info[num_ahb_clk].clk_rate =
				clk_info[i].clk_rate;
			CDBG("clk_name[%d]= %s, clk_rate = %ld\n",
				num_ahb_clk, ahb_clk_info[num_ahb_clk].clk_name,
				ahb_clk_info[num_ahb_clk].clk_rate);
			num_ahb_clk++;
		}
	}
	CDBG("%s: num_ahb_clk %d num_clk %d\n", __func__, num_ahb_clk, count);
	ispif_dev->num_ahb_clk = num_ahb_clk;
	ispif_dev->num_clk = count;
	return 0;
}
Esempio n. 8
0
static int mdss_dsi_get_dt_vreg_data(struct device *dev,
                                     struct dss_module_power *mp)
{
    int i, rc = 0;
    int dt_vreg_total = 0;
    u32 *val_array = NULL;
    struct device_node *of_node = NULL;

    if (!dev || !mp) {
        pr_err("%s: invalid input\n", __func__);
        rc = -EINVAL;
        goto error;
    }

    of_node = dev->of_node;

    mp->num_vreg = 0;
    dt_vreg_total = of_property_count_strings(of_node, "qcom,supply-names");
    if (dt_vreg_total < 0) {
        pr_debug("%s: vreg not found. rc=%d\n", __func__,
                 dt_vreg_total);
        rc = 0;
        goto error;
    } else {
        pr_debug("%s: vreg found. count=%d\n", __func__, dt_vreg_total);
    }

    if (dt_vreg_total > 0) {
        mp->num_vreg = dt_vreg_total;
        mp->vreg_config = devm_kzalloc(dev, sizeof(struct dss_vreg) *
                                       dt_vreg_total, GFP_KERNEL);
        if (!mp->vreg_config) {
            pr_err("%s: can't alloc vreg mem\n", __func__);
            goto error;
        }
    } else {
        pr_debug("%s: no vreg\n", __func__);
        return 0;
    }

    val_array = devm_kzalloc(dev, sizeof(u32) * dt_vreg_total, GFP_KERNEL);
    if (!val_array) {
        pr_err("%s: can't allocate vreg scratch mem\n", __func__);
        rc = -ENOMEM;
        goto error;
    }

    for (i = 0; i < dt_vreg_total; i++) {
        const char *st = NULL;
        /* vreg-name */
        rc = of_property_read_string_index(of_node, "qcom,supply-names",
                                           i, &st);
        if (rc) {
            pr_err("%s: error reading name. i=%d, rc=%d\n",
                   __func__, i, rc);
            goto error;
        }
        snprintf(mp->vreg_config[i].vreg_name,
                 ARRAY_SIZE((mp->vreg_config[i].vreg_name)), "%s", st);

        /* vreg-min-voltage */
        memset(val_array, 0, sizeof(u32) * dt_vreg_total);
        rc = of_property_read_u32_array(of_node,
                                        "qcom,supply-min-voltage-level", val_array,
                                        dt_vreg_total);
        if (rc) {
            pr_err("%s: error reading min volt. rc=%d\n",
                   __func__, rc);
            goto error;
        }
        mp->vreg_config[i].min_voltage = val_array[i];

        /* vreg-max-voltage */
        memset(val_array, 0, sizeof(u32) * dt_vreg_total);
        rc = of_property_read_u32_array(of_node,
                                        "qcom,supply-max-voltage-level", val_array,
                                        dt_vreg_total);
        if (rc) {
            pr_err("%s: error reading max volt. rc=%d\n",
                   __func__, rc);
            goto error;
        }
        mp->vreg_config[i].max_voltage = val_array[i];

        /* vreg-peak-current*/
        memset(val_array, 0, sizeof(u32) * dt_vreg_total);
        rc = of_property_read_u32_array(of_node,
                                        "qcom,supply-peak-current", val_array,
                                        dt_vreg_total);
        if (rc) {
            pr_err("%s: error reading peak current. rc=%d\n",
                   __func__, rc);
            goto error;
        }
        mp->vreg_config[i].peak_current = val_array[i];

        pr_debug("%s: %s min=%d, max=%d, pc=%d\n", __func__,
                 mp->vreg_config[i].vreg_name,
                 mp->vreg_config[i].min_voltage,
                 mp->vreg_config[i].max_voltage,
                 mp->vreg_config[i].peak_current);
    }

    devm_kfree(dev, val_array);

    return rc;

error:
    if (mp->vreg_config) {
        devm_kfree(dev, mp->vreg_config);
        mp->vreg_config = NULL;
    }
    mp->num_vreg = 0;

    if (val_array)
        devm_kfree(dev, val_array);
    return rc;
}
/**********************************************************
*  Function:       charge_core_parse_dts
*  Discription:    parse the module dts config value
*  Parameters:   np:device_node
*                      di:charge_core_info
*  return value:  0-sucess or others-fail
**********************************************************/
static int charge_core_parse_dts(struct device_node* np, struct charge_core_info *di)
{
    int ret = 0;
    int i = 0;
    int array_len = 0;
    int idata = 0;
    const char *chrg_data_string = NULL;

    /*ac charge current*/
    ret = of_property_read_u32(np, "iin_ac", &(di->data.iin_ac));
    if(ret)
    {
        hwlog_err("get iin_ac failed\n");
        return -EINVAL;
    }
    hwlog_debug("iin_ac = %d\n",di->data.iin_ac);
    ret = of_property_read_u32(np, "ichg_ac", &(di->data.ichg_ac));
    if(ret)
    {
        hwlog_err("get ichg_ac failed\n");
        return -EINVAL;
    }
    hwlog_debug("ichg_ac = %d\n",di->data.ichg_ac);

    /*fcp charge current */
    ret = of_property_read_u32(np,"iin_fcp",&(di->data.iin_fcp));
    if(ret)
    {
        hwlog_info("get iin_fcp failed ,use iin_ac's value instead \n");
        di->data.iin_fcp = di->data.iin_ac;
    }
    hwlog_debug("iin_fcp = %d\n",di->data.iin_fcp);
    ret = of_property_read_u32(np,"ichg_fcp",&(di->data.ichg_fcp));
    if(ret)
    {
        hwlog_info("get ichg_fcp failed ,use ichg_ac's value instead \n");
        di->data.ichg_fcp = di->data.ichg_ac;
    }
    hwlog_debug("ichg_fcp = %d\n",di->data.ichg_fcp);

    /*usb charge current*/
    ret = of_property_read_u32(np, "iin_usb", &(di->data.iin_usb));
    if(ret)
    {
        hwlog_err("get iin_usb failed\n");
        return -EINVAL;
    }
    hwlog_debug("iin_usb = %d\n",di->data.iin_usb);
    ret = of_property_read_u32(np, "ichg_usb", &(di->data.ichg_usb));
    if(ret)
    {
        hwlog_err("get ichg_usb failed\n");
        return -EINVAL;
    }
    hwlog_debug("ichg_usb = %d\n",di->data.ichg_usb);
    /*nonstandard charge current*/
    ret = of_property_read_u32(np, "iin_nonstd", &(di->data.iin_nonstd));
    if(ret)
    {
        hwlog_err("get iin_nonstd failed\n");
        return -EINVAL;
    }
    hwlog_debug("iin_nonstd = %d\n",di->data.iin_nonstd);
    ret = of_property_read_u32(np, "ichg_nonstd", &(di->data.ichg_nonstd));
    if(ret)
    {
        hwlog_err("get ichg_nonstd failed\n");
        return -EINVAL;
    }
    hwlog_debug("ichg_nonstd = %d\n",di->data.ichg_nonstd);
    /*Charging Downstream Port*/
    ret = of_property_read_u32(np, "iin_bc_usb", &(di->data.iin_bc_usb));
    if(ret)
    {
        hwlog_err("get iin_bc_usb failed\n");
        return -EINVAL;
    }
    hwlog_debug("iin_bc_usb = %d\n",di->data.iin_bc_usb);
    ret = of_property_read_u32(np, "ichg_bc_usb", &(di->data.ichg_bc_usb));
    if(ret)
    {
        hwlog_err("get ichg_bc_usb failed\n");
        return -EINVAL;
    }
    hwlog_debug("ichg_bc_usb = %d\n",di->data.ichg_bc_usb);
    /*VR Charge current*/
    ret = of_property_read_u32(np, "iin_vr", &(di->data.iin_vr));
    if(ret)
    {
        hwlog_err("get iin_vr failed\n");
        return -EINVAL;
    }
    hwlog_debug("iin_vr = %d\n",di->data.iin_vr);
    ret = of_property_read_u32(np, "ichg_vr", &(di->data.ichg_vr));
    if(ret)
    {
        hwlog_err("get ichg_vr failed\n");
        return -EINVAL;
    }
    hwlog_debug("ichg_vr = %d\n",di->data.ichg_vr);
    /*terminal current*/
    ret = of_property_read_u32(np, "iterm", &(di->data.iterm));
    if(ret)
    {
        hwlog_err("get iterm failed\n");
        return -EINVAL;
    }
    hwlog_debug("iterm = %d\n",di->data.iterm);
    /*otg current*/
    ret = of_property_read_u32(np, "otg_curr", &(di->data.otg_curr));
    if(ret)
    {
        hwlog_err("get otg_curr failed\n");
        return -EINVAL;
    }
    hwlog_debug("otg_curr = %d\n",di->data.otg_curr);
    /*segment para type*/
    ret = of_property_read_u32(np, "segment_type", &(di->data.segment_type));
    if(ret)
    {
        hwlog_err("get segment_type failed\n");
        return -EINVAL;
    }
    /*TypeC High mode current*/
    ret = of_property_read_u32(np, "typec_support", &(di->data.typec_support));
    if(ret)
    {
        hwlog_err("get typec support flag!\n");
        return -EINVAL;
    }
    hwlog_info("typec support flag = %d\n",di->data.typec_support);

    ret = of_property_read_u32(np, "iin_typech", &(di->data.iin_typech));
    if(ret)
    {
        hwlog_err("get typec high mode ibus curr failed\n");
        return -EINVAL;
    }
    hwlog_info("typec high mode ibus curr = %d\n",di->data.iin_typech);
    ret = of_property_read_u32(np, "ichg_typech", &(di->data.ichg_typech));
    if(ret)
    {
        hwlog_err("get typec high mode ibat curr failed\n");
        return -EINVAL;
    }
    hwlog_info("typec high mode ibat curr = %d\n",di->data.ichg_typech);
    //vdpm_para
    array_len = of_property_count_strings(np, "vdpm_para");
    if ((array_len <= 0) || (array_len % VDPM_PARA_TOTAL != 0))
    {
        hwlog_err("vdpm_para is invaild,please check vdpm_para number!!\n");
        return -EINVAL;
    }

    if (array_len > VDPM_PARA_LEVEL * VDPM_PARA_TOTAL)
    {
        array_len = VDPM_PARA_LEVEL * VDPM_PARA_TOTAL;
        hwlog_err("vdpm_para is too long,use only front %d paras!!\n", array_len);
        return -EINVAL;
    }

    memset(di->vdpm_para, 0, VDPM_PARA_LEVEL * sizeof(struct charge_vdpm_data)); // data reset to 0

    for (i = 0; i < array_len; i++)
    {
        ret = of_property_read_string_index(np, "vdpm_para", i, &chrg_data_string);
        if (ret)
        {
            hwlog_err("get vdpm_para failed\n");
            return -EINVAL;
        }

        idata = simple_strtol(chrg_data_string, NULL, 10);
        switch (i % VDPM_PARA_TOTAL)
        {
            case VDPM_PARA_CAP_MIN:
                if ((idata < VDPM_CBAT_MIN) || (idata > VDPM_CBAT_MAX))
                {
                    hwlog_err("the vdpm_para cap_min is out of range!!\n");
                    return -EINVAL;
                }
                di->vdpm_para[ i/ (VDPM_PARA_TOTAL)].cap_min = idata;
                break;
            case VDPM_PARA_CAP_MAX:
                if((idata < VDPM_CBAT_MIN) || (idata > VDPM_CBAT_MAX))
                {
                    hwlog_err("the vdpm_para cap_max is out of range!!\n");
                    return -EINVAL;
                }
                di->vdpm_para[i / (VDPM_PARA_TOTAL)].cap_max = idata;
                break;
            case VDPM_PARA_DPM:
                if((idata < VDPM_VOLT_MIN) || (idata > VDPM_VOLT_MAX))
                {
                    hwlog_err("the vdpm_para vin_dpm is out of range!!\n");
                    return -EINVAL;
                }
                di->vdpm_para[i / (VDPM_PARA_TOTAL)].vin_dpm = idata;
                break;
            case VDPM_PARA_CAP_BACK:
                if((idata < 0) || (idata > VDPM_CAP_DETA))
                {
                    hwlog_err("the vdpm_para cap_back is out of range!!\n");
                    return -EINVAL;
                }
                di->vdpm_para[i / (VDPM_PARA_TOTAL)].cap_back = idata;
                break;
            default:
                hwlog_err("get vdpm_para failed\n");
        }
        hwlog_debug("di->vdpm_para[%d][%d] = %d\n", i / (VDPM_PARA_TOTAL),
                   i % (VDPM_PARA_TOTAL), idata);
    }

    /* inductance_para */
    memset(di->inductance_para, 0, INDUCTANCE_PARA_LEVEL * sizeof(struct charge_inductance_data)); // data reset to 0

    array_len = of_property_count_strings(np, "inductance_para");
    if ((array_len <= 0) || (array_len % INDUCTANCE_PARA_TOTAL != 0))
    {
        hwlog_err("inductance_para is invaild,please check inductance_para number!!\n");
        return -EINVAL;
    }
    if (array_len > INDUCTANCE_PARA_LEVEL * INDUCTANCE_PARA_TOTAL)
    {
        array_len = INDUCTANCE_PARA_LEVEL * INDUCTANCE_PARA_TOTAL;
        hwlog_err("inductance_para is too long,use only front %d paras!!\n", array_len);
        return -EINVAL;
    }

    for(i = 0; i < array_len ; i++)
    {
        ret = of_property_read_string_index(np, "inductance_para", i, &chrg_data_string);
        if (ret)
         {
             hwlog_err("get inductance_para failed\n");
             return -EINVAL;
         }

        idata = simple_strtol(chrg_data_string, NULL, 10);
        switch (i % INDUCTANCE_PARA_TOTAL)
        {
            case INDUCTANCE_PARA_CAP_MIN:
                if ((idata < INDUCTANCE_CBAT_MIN) || (idata > INDUCTANCE_CBAT_MAX))
                {
                    hwlog_err("the inductance_para cap_min is out of range!!\n");
                    return -EINVAL;
                }
                di->inductance_para[ i/ (INDUCTANCE_PARA_TOTAL)].cap_min = idata;
                break;
            case INDUCTANCE_PARA_CAP_MAX:
                if ((idata < INDUCTANCE_CBAT_MIN) || (idata > INDUCTANCE_CBAT_MAX))
                {
                    hwlog_err("the inductance_para cap_max is out of range!!\n");
                    return -EINVAL;
                }
                di->inductance_para[i / (INDUCTANCE_PARA_TOTAL)].cap_max = idata;
                break;
            case INDUCTANCE_PARA_IIN:
                if ((idata < INDUCTANCE_IIN_MIN) || (idata > INDUCTANCE_IIN_MAX))
                {
                    hwlog_err("the inductance_para iin is out of range!!\n");
                    return -EINVAL;
                }
                di->inductance_para[i / (INDUCTANCE_PARA_TOTAL)].iin_inductance= idata;
                break;
            case INDUCTANCE_PARA_CAP_BACK:
                if ((idata < 0) || (idata > INDUCTANCE_CAP_DETA))
                {
                    hwlog_err("the inductance_para cap_back is out of range!!\n");
                    return -EINVAL;
                }
                di->inductance_para[i / (INDUCTANCE_PARA_TOTAL)].cap_back = idata;
                break;
            default:
                hwlog_err("get vdpm_para failed\n");
        }
        hwlog_info("di->inductance_para[%d][%d] = %d\n", i / (INDUCTANCE_PARA_TOTAL),
           i % (INDUCTANCE_PARA_TOTAL), idata);
    }

    if(strstr(saved_command_line, "androidboot.swtype=factory") && (!is_hisi_battery_exist()))
    {
        di->data.iin_ac = CHARGE_CURRENT_2000_MA;
        di->data.ichg_ac = CHARGE_CURRENT_1900_MA;
        di->data.iin_bc_usb = CHARGE_CURRENT_2000_MA;
        di->data.ichg_bc_usb = CHARGE_CURRENT_1900_MA;
        hwlog_info("factory version,iin_ac = %d mA,ichg_ac %d mA,iin_bc_usb = %d mA,ichg_bc_usb = %d mA\n",
            di->data.iin_ac,di->data.ichg_ac,di->data.iin_bc_usb,di->data.ichg_bc_usb);
    }
    di->data.iin_max = di->data.iin_ac < di->data.iin_fcp ? di->data.iin_fcp :di->data.iin_ac;
    di->data.ichg_max = di->data.ichg_ac < di->data.ichg_fcp ? di->data.ichg_fcp :di->data.ichg_ac;
    hwlog_info("iin_max = %d mA,ichg_max %d mA\n",di->data.iin_max,di->data.ichg_max);
    return 0;
}
Esempio n. 10
0
static void __init zynq_periph_clk_setup(struct device_node *np)
{
	struct zynq_periph_clk *periph;
	const char *parent_names[3];
	struct clk_init_data init;
	int clk_num = 0, err;
	const char *name;
	struct clk *clk;
	u32 reg;
	int i;

	err = of_property_read_u32(np, "reg", &reg);
	if (WARN_ON(err))
		return;

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

	periph->clk_ctrl = slcr_base + reg;
	spin_lock_init(&periph->clkact_lock);

	init.name = np->name;
	init.ops = &zynq_periph_clk_ops;
	for (i = 0; i < ARRAY_SIZE(parent_names); i++)
		parent_names[i] = of_clk_get_parent_name(np, i);
	init.parent_names = parent_names;
	init.num_parents = ARRAY_SIZE(parent_names);

	periph->hw.init = &init;

	clk = clk_register(NULL, &periph->hw);
	if (WARN_ON(IS_ERR(clk)))
		return;

	err = of_clk_add_provider(np, of_clk_src_simple_get, clk);
	if (WARN_ON(err))
		return;

	err = of_property_read_string_index(np, "clock-output-names", 0,
					    &name);
	if (WARN_ON(err))
		return;

	periph->gates[0] = clk_register_gate(NULL, name, np->name, 0,
					     periph->clk_ctrl, 0, 0,
					     &periph->clkact_lock);
	if (WARN_ON(IS_ERR(periph->gates[0])))
		return;
	clk_num++;

	/* some periph clks have 2 downstream gates */
	err = of_property_read_string_index(np, "clock-output-names", 1,
					    &name);
	if (err != -ENODATA) {
		periph->gates[1] = clk_register_gate(NULL, name, np->name, 0,
						     periph->clk_ctrl, 1, 0,
						     &periph->clkact_lock);
		if (WARN_ON(IS_ERR(periph->gates[1])))
			return;
		clk_num++;
	}

	periph->onecell_data.clks = periph->gates;
	periph->onecell_data.clk_num = clk_num;

	err = of_clk_add_provider(np, of_clk_src_onecell_get,
				  &periph->onecell_data);
	if (WARN_ON(err))
		return;
}
Esempio n. 11
0
static int msm_csid_get_clk_info(struct csid_device *csid_dev,
	struct platform_device *pdev)
{
	uint32_t count;
	uint32_t cnt = 0;
	int i, rc;
	int ii = 0;
	uint32_t rates[CSID_NUM_CLK_MAX];
	const char *clock_name;
	struct device_node *of_node;
	of_node = pdev->dev.of_node;

	count = of_property_count_strings(of_node, "qcom,clock-names");
	csid_dev->num_clk = count;

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

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

	if (csid_dev->hw_dts_version == CSID_VERSION_V22) {
		cnt = count;
		count = 0;
		CDBG("%s: cnt = %d\n", __func__, cnt);
		if (cnt == 0) {
			pr_err("%s: no clocks found in device tree, cnt=%d",
				__func__, cnt);
			return -EINVAL;
		}

		if (cnt > CSID_NUM_CLK_MAX) {
			pr_err("%s: invalid cnt=%d, max is %d\n", __func__,
				cnt, CSID_NUM_CLK_MAX);
			return -EINVAL;
		}

		for (i = 0; i < cnt; i++) {
			count++;
			rc = of_property_read_string_index(of_node,
				"qcom,clock-names", i, &clock_name);
			CDBG("%s: clock_names[%d] = %s\n", __func__,
				i, clock_name);
			if (rc < 0) {
				pr_err("%s:%d, failed\n", __func__, __LINE__);
				return rc;
			}
			if (strcmp(clock_name, "csi_phy_src_clk") == 0)
				break;
		}
		csid_dev->num_clk = count;
	}

	for (i = 0; i < count; i++) {
		rc = of_property_read_string_index(of_node, "qcom,clock-names",
				i, &(csid_clk_info[i].clk_name));
		CDBG("%s: clock-names[%d] = %s\n", __func__,
			i, csid_clk_info[i].clk_name);
		if (rc < 0) {
			pr_err("%s:%d, failed\n", __func__, __LINE__);
			return rc;
		}
	}
	rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
		rates, count);
	if (rc < 0) {
		pr_err("%s:%d, failed", __func__, __LINE__);
		return rc;
	}
	for (i = 0; i < count; i++) {
		csid_clk_info[i].clk_rate = (rates[i] == 0) ? -1 : rates[i];
		CDBG("%s: clk_rate[%d] = %ld\n", __func__, i,
			csid_clk_info[i].clk_rate);
	}

	if (csid_dev->hw_dts_version == CSID_VERSION_V22) {
		csid_dev->num_clk_src_info = cnt - count;
		CDBG("%s: count = %d\n", __func__, (cnt - count));

		for (i = count; i < cnt; i++) {
			ii++;
			rc = of_property_read_string_index(of_node,
				"qcom,clock-names", i,
				&(csid_clk_src_info[ii].clk_name));
			CDBG("%s: clock-names[%d] = %s\n", __func__,
				ii, csid_clk_src_info[ii].clk_name);
			if (rc < 0) {
				pr_err("%s:%d, failed\n", __func__, __LINE__);
				return rc;
			}
		}
		ii = 0;
		rc = of_property_read_u32_array(of_node, "qcom,clock-rates",
			rates, cnt);
		if (rc < 0) {
			pr_err("%s:%d, failed", __func__, __LINE__);
			return rc;
		}
		for (i = count; i < cnt; i++) {
			ii++;
			csid_clk_src_info[ii].clk_rate = rates[i];
			CDBG("%s: clk_rate[%d] = %ld\n", __func__, ii,
			csid_clk_src_info[ii].clk_rate);
		}
	}
	return 0;
}
Esempio n. 12
0
static void __init zynq_clk_setup(struct device_node *np)
{
    int i;
    u32 tmp;
    int ret;
    struct clk *clk;
    char *clk_name;
    const char *clk_output_name[clk_max];
    const char *cpu_parents[4];
    const char *periph_parents[4];
    const char *swdt_ext_clk_mux_parents[2];
    const char *can_mio_mux_parents[NUM_MIO_PINS];

    pr_info("Zynq clock init\n");

    /* get clock output names from DT */
    for (i = 0; i < clk_max; i++) {
        if (of_property_read_string_index(np, "clock-output-names",
                                          i, &clk_output_name[i])) {
            pr_err("%s: clock output name not in DT\n", __func__);
            BUG();
        }
    }
    cpu_parents[0] = clk_output_name[armpll];
    cpu_parents[1] = clk_output_name[armpll];
    cpu_parents[2] = clk_output_name[ddrpll];
    cpu_parents[3] = clk_output_name[iopll];
    periph_parents[0] = clk_output_name[iopll];
    periph_parents[1] = clk_output_name[iopll];
    periph_parents[2] = clk_output_name[armpll];
    periph_parents[3] = clk_output_name[ddrpll];

    /* ps_clk */
    ret = of_property_read_u32(np, "ps-clk-frequency", &tmp);
    if (ret) {
        pr_warn("ps_clk frequency not specified, using 33 MHz.\n");
        tmp = 33333333;
    }
    ps_clk = clk_register_fixed_rate(NULL, "ps_clk", NULL, CLK_IS_ROOT,
                                     tmp);

    /* PLLs */
    clk = clk_register_zynq_pll("armpll_int", "ps_clk", SLCR_ARMPLL_CTRL,
                                SLCR_PLL_STATUS, 0, &armpll_lock);
    clks[armpll] = clk_register_mux(NULL, clk_output_name[armpll],
                                    armpll_parents, 2, 0, SLCR_ARMPLL_CTRL, 4, 1, 0,
                                    &armpll_lock);

    clk = clk_register_zynq_pll("ddrpll_int", "ps_clk", SLCR_DDRPLL_CTRL,
                                SLCR_PLL_STATUS, 1, &ddrpll_lock);
    clks[ddrpll] = clk_register_mux(NULL, clk_output_name[ddrpll],
                                    ddrpll_parents, 2, 0, SLCR_DDRPLL_CTRL, 4, 1, 0,
                                    &ddrpll_lock);

    clk = clk_register_zynq_pll("iopll_int", "ps_clk", SLCR_IOPLL_CTRL,
                                SLCR_PLL_STATUS, 2, &iopll_lock);
    clks[iopll] = clk_register_mux(NULL, clk_output_name[iopll],
                                   iopll_parents, 2, 0, SLCR_IOPLL_CTRL, 4, 1, 0,
                                   &iopll_lock);

    /* CPU clocks */
    tmp = readl(SLCR_621_TRUE) & 1;
    clk = clk_register_mux(NULL, "cpu_mux", cpu_parents, 4, 0,
                           SLCR_ARM_CLK_CTRL, 4, 2, 0, &armclk_lock);
    clk = clk_register_divider(NULL, "cpu_div", "cpu_mux", 0,
                               SLCR_ARM_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                               CLK_DIVIDER_ALLOW_ZERO, &armclk_lock);

    clks[cpu_6or4x] = clk_register_gate(NULL, clk_output_name[cpu_6or4x],
                                        "cpu_div", CLK_SET_RATE_PARENT | CLK_IGNORE_UNUSED,
                                        SLCR_ARM_CLK_CTRL, 24, 0, &armclk_lock);

    clk = clk_register_fixed_factor(NULL, "cpu_3or2x_div", "cpu_div", 0,
                                    1, 2);
    clks[cpu_3or2x] = clk_register_gate(NULL, clk_output_name[cpu_3or2x],
                                        "cpu_3or2x_div", CLK_IGNORE_UNUSED,
                                        SLCR_ARM_CLK_CTRL, 25, 0, &armclk_lock);

    clk = clk_register_fixed_factor(NULL, "cpu_2x_div", "cpu_div", 0, 1,
                                    2 + tmp);
    clks[cpu_2x] = clk_register_gate(NULL, clk_output_name[cpu_2x],
                                     "cpu_2x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL,
                                     26, 0, &armclk_lock);

    clk = clk_register_fixed_factor(NULL, "cpu_1x_div", "cpu_div", 0, 1,
                                    4 + 2 * tmp);
    clks[cpu_1x] = clk_register_gate(NULL, clk_output_name[cpu_1x],
                                     "cpu_1x_div", CLK_IGNORE_UNUSED, SLCR_ARM_CLK_CTRL, 27,
                                     0, &armclk_lock);

    /* Timers */
    swdt_ext_clk_mux_parents[0] = clk_output_name[cpu_1x];
    for (i = 0; i < ARRAY_SIZE(swdt_ext_clk_input_names); i++) {
        int idx = of_property_match_string(np, "clock-names",
                                           swdt_ext_clk_input_names[i]);
        if (idx >= 0)
            swdt_ext_clk_mux_parents[i + 1] =
                of_clk_get_parent_name(np, idx);
        else
            swdt_ext_clk_mux_parents[i + 1] = dummy_nm;
    }
    clks[swdt] = clk_register_mux(NULL, clk_output_name[swdt],
                                  swdt_ext_clk_mux_parents, 2, CLK_SET_RATE_PARENT,
                                  SLCR_SWDT_CLK_SEL, 0, 1, 0, &gem0clk_lock);

    /* DDR clocks */
    clk = clk_register_divider(NULL, "ddr2x_div", "ddrpll", 0,
                               SLCR_DDR_CLK_CTRL, 26, 6, CLK_DIVIDER_ONE_BASED |
                               CLK_DIVIDER_ALLOW_ZERO, &ddrclk_lock);
    clks[ddr2x] = clk_register_gate(NULL, clk_output_name[ddr2x],
                                    "ddr2x_div", 0, SLCR_DDR_CLK_CTRL, 1, 0, &ddrclk_lock);
    clk_prepare_enable(clks[ddr2x]);
    clk = clk_register_divider(NULL, "ddr3x_div", "ddrpll", 0,
                               SLCR_DDR_CLK_CTRL, 20, 6, CLK_DIVIDER_ONE_BASED |
                               CLK_DIVIDER_ALLOW_ZERO, &ddrclk_lock);
    clks[ddr3x] = clk_register_gate(NULL, clk_output_name[ddr3x],
                                    "ddr3x_div", 0, SLCR_DDR_CLK_CTRL, 0, 0, &ddrclk_lock);
    clk_prepare_enable(clks[ddr3x]);

    clk = clk_register_divider(NULL, "dci_div0", "ddrpll", 0,
                               SLCR_DCI_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                               CLK_DIVIDER_ALLOW_ZERO, &dciclk_lock);
    clk = clk_register_divider(NULL, "dci_div1", "dci_div0",
                               CLK_SET_RATE_PARENT, SLCR_DCI_CLK_CTRL, 20, 6,
                               CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                               &dciclk_lock);
    clks[dci] = clk_register_gate(NULL, clk_output_name[dci], "dci_div1",
                                  CLK_SET_RATE_PARENT, SLCR_DCI_CLK_CTRL, 0, 0,
                                  &dciclk_lock);
    clk_prepare_enable(clks[dci]);

    /* Peripheral clocks */
    for (i = fclk0; i <= fclk3; i++)
        zynq_clk_register_fclk(i, clk_output_name[i],
                               SLCR_FPGA0_CLK_CTRL + 0x10 * (i - fclk0),
                               periph_parents);

    zynq_clk_register_periph_clk(lqspi, 0, clk_output_name[lqspi], NULL,
                                 SLCR_LQSPI_CLK_CTRL, periph_parents, 0);

    zynq_clk_register_periph_clk(smc, 0, clk_output_name[smc], NULL,
                                 SLCR_SMC_CLK_CTRL, periph_parents, 0);

    zynq_clk_register_periph_clk(pcap, 0, clk_output_name[pcap], NULL,
                                 SLCR_PCAP_CLK_CTRL, periph_parents, 0);

    zynq_clk_register_periph_clk(sdio0, sdio1, clk_output_name[sdio0],
                                 clk_output_name[sdio1], SLCR_SDIO_CLK_CTRL,
                                 periph_parents, 1);

    zynq_clk_register_periph_clk(uart0, uart1, clk_output_name[uart0],
                                 clk_output_name[uart1], SLCR_UART_CLK_CTRL,
                                 periph_parents, 1);

    zynq_clk_register_periph_clk(spi0, spi1, clk_output_name[spi0],
                                 clk_output_name[spi1], SLCR_SPI_CLK_CTRL,
                                 periph_parents, 1);

    for (i = 0; i < ARRAY_SIZE(gem0_emio_input_names); i++) {
        int idx = of_property_match_string(np, "clock-names",
                                           gem0_emio_input_names[i]);
        if (idx >= 0)
            gem0_mux_parents[i + 1] = of_clk_get_parent_name(np,
                                      idx);
    }
    clk = clk_register_mux(NULL, "gem0_mux", periph_parents, 4, 0,
                           SLCR_GEM0_CLK_CTRL, 4, 2, 0, &gem0clk_lock);
    clk = clk_register_divider(NULL, "gem0_div0", "gem0_mux", 0,
                               SLCR_GEM0_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                               CLK_DIVIDER_ALLOW_ZERO, &gem0clk_lock);
    clk = clk_register_divider(NULL, "gem0_div1", "gem0_div0",
                               CLK_SET_RATE_PARENT, SLCR_GEM0_CLK_CTRL, 20, 6,
                               CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                               &gem0clk_lock);
    clk = clk_register_mux(NULL, "gem0_emio_mux", gem0_mux_parents, 2, 0,
                           SLCR_GEM0_CLK_CTRL, 6, 1, 0, &gem0clk_lock);
    clks[gem0] = clk_register_gate(NULL, clk_output_name[gem0],
                                   "gem0_emio_mux", CLK_SET_RATE_PARENT,
                                   SLCR_GEM0_CLK_CTRL, 0, 0, &gem0clk_lock);

    for (i = 0; i < ARRAY_SIZE(gem1_emio_input_names); i++) {
        int idx = of_property_match_string(np, "clock-names",
                                           gem1_emio_input_names[i]);
        if (idx >= 0)
            gem1_mux_parents[i + 1] = of_clk_get_parent_name(np,
                                      idx);
    }
    clk = clk_register_mux(NULL, "gem1_mux", periph_parents, 4, 0,
                           SLCR_GEM1_CLK_CTRL, 4, 2, 0, &gem1clk_lock);
    clk = clk_register_divider(NULL, "gem1_div0", "gem1_mux", 0,
                               SLCR_GEM1_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                               CLK_DIVIDER_ALLOW_ZERO, &gem1clk_lock);
    clk = clk_register_divider(NULL, "gem1_div1", "gem1_div0",
                               CLK_SET_RATE_PARENT, SLCR_GEM1_CLK_CTRL, 20, 6,
                               CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                               &gem1clk_lock);
    clk = clk_register_mux(NULL, "gem1_emio_mux", gem1_mux_parents, 2, 0,
                           SLCR_GEM1_CLK_CTRL, 6, 1, 0, &gem1clk_lock);
    clks[gem1] = clk_register_gate(NULL, clk_output_name[gem1],
                                   "gem1_emio_mux", CLK_SET_RATE_PARENT,
                                   SLCR_GEM1_CLK_CTRL, 0, 0, &gem1clk_lock);

    tmp = strlen("mio_clk_00x");
    clk_name = kmalloc(tmp, GFP_KERNEL);
    for (i = 0; i < NUM_MIO_PINS; i++) {
        int idx;

        snprintf(clk_name, tmp, "mio_clk_%2.2d", i);
        idx = of_property_match_string(np, "clock-names", clk_name);
        if (idx >= 0)
            can_mio_mux_parents[i] = of_clk_get_parent_name(np,
                                     idx);
        else
            can_mio_mux_parents[i] = dummy_nm;
    }
    kfree(clk_name);
    clk = clk_register_mux(NULL, "can_mux", periph_parents, 4, 0,
                           SLCR_CAN_CLK_CTRL, 4, 2, 0, &canclk_lock);
    clk = clk_register_divider(NULL, "can_div0", "can_mux", 0,
                               SLCR_CAN_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                               CLK_DIVIDER_ALLOW_ZERO, &canclk_lock);
    clk = clk_register_divider(NULL, "can_div1", "can_div0",
                               CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 20, 6,
                               CLK_DIVIDER_ONE_BASED | CLK_DIVIDER_ALLOW_ZERO,
                               &canclk_lock);
    clk = clk_register_gate(NULL, "can0_gate", "can_div1",
                            CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 0, 0,
                            &canclk_lock);
    clk = clk_register_gate(NULL, "can1_gate", "can_div1",
                            CLK_SET_RATE_PARENT, SLCR_CAN_CLK_CTRL, 1, 0,
                            &canclk_lock);
    clk = clk_register_mux(NULL, "can0_mio_mux",
                           can_mio_mux_parents, 54, CLK_SET_RATE_PARENT,
                           SLCR_CAN_MIOCLK_CTRL, 0, 6, 0, &canmioclk_lock);
    clk = clk_register_mux(NULL, "can1_mio_mux",
                           can_mio_mux_parents, 54, CLK_SET_RATE_PARENT,
                           SLCR_CAN_MIOCLK_CTRL, 16, 6, 0, &canmioclk_lock);
    clks[can0] = clk_register_mux(NULL, clk_output_name[can0],
                                  can0_mio_mux2_parents, 2, CLK_SET_RATE_PARENT,
                                  SLCR_CAN_MIOCLK_CTRL, 6, 1, 0, &canmioclk_lock);
    clks[can1] = clk_register_mux(NULL, clk_output_name[can1],
                                  can1_mio_mux2_parents, 2, CLK_SET_RATE_PARENT,
                                  SLCR_CAN_MIOCLK_CTRL, 22, 1, 0, &canmioclk_lock);

    for (i = 0; i < ARRAY_SIZE(dbgtrc_emio_input_names); i++) {
        int idx = of_property_match_string(np, "clock-names",
                                           dbgtrc_emio_input_names[i]);
        if (idx >= 0)
            dbg_emio_mux_parents[i + 1] = of_clk_get_parent_name(np,
                                          idx);
    }
    clk = clk_register_mux(NULL, "dbg_mux", periph_parents, 4, 0,
                           SLCR_DBG_CLK_CTRL, 4, 2, 0, &dbgclk_lock);
    clk = clk_register_divider(NULL, "dbg_div", "dbg_mux", 0,
                               SLCR_DBG_CLK_CTRL, 8, 6, CLK_DIVIDER_ONE_BASED |
                               CLK_DIVIDER_ALLOW_ZERO, &dbgclk_lock);
    clk = clk_register_mux(NULL, "dbg_emio_mux", dbg_emio_mux_parents, 2, 0,
                           SLCR_DBG_CLK_CTRL, 6, 1, 0, &dbgclk_lock);
    clks[dbg_trc] = clk_register_gate(NULL, clk_output_name[dbg_trc],
                                      "dbg_emio_mux", CLK_SET_RATE_PARENT, SLCR_DBG_CLK_CTRL,
                                      0, 0, &dbgclk_lock);
    clks[dbg_apb] = clk_register_gate(NULL, clk_output_name[dbg_apb],
                                      clk_output_name[cpu_1x], 0, SLCR_DBG_CLK_CTRL, 1, 0,
                                      &dbgclk_lock);

    /* One gated clock for all APER clocks. */
    clks[dma] = clk_register_gate(NULL, clk_output_name[dma],
                                  clk_output_name[cpu_2x], 0, SLCR_APER_CLK_CTRL, 0, 0,
                                  &aperclk_lock);
    clks[usb0_aper] = clk_register_gate(NULL, clk_output_name[usb0_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 2, 0,
                                        &aperclk_lock);
    clks[usb1_aper] = clk_register_gate(NULL, clk_output_name[usb1_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 3, 0,
                                        &aperclk_lock);
    clks[gem0_aper] = clk_register_gate(NULL, clk_output_name[gem0_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 6, 0,
                                        &aperclk_lock);
    clks[gem1_aper] = clk_register_gate(NULL, clk_output_name[gem1_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 7, 0,
                                        &aperclk_lock);
    clks[sdio0_aper] = clk_register_gate(NULL, clk_output_name[sdio0_aper],
                                         clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 10, 0,
                                         &aperclk_lock);
    clks[sdio1_aper] = clk_register_gate(NULL, clk_output_name[sdio1_aper],
                                         clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 11, 0,
                                         &aperclk_lock);
    clks[spi0_aper] = clk_register_gate(NULL, clk_output_name[spi0_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 14, 0,
                                        &aperclk_lock);
    clks[spi1_aper] = clk_register_gate(NULL, clk_output_name[spi1_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 15, 0,
                                        &aperclk_lock);
    clks[can0_aper] = clk_register_gate(NULL, clk_output_name[can0_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 16, 0,
                                        &aperclk_lock);
    clks[can1_aper] = clk_register_gate(NULL, clk_output_name[can1_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 17, 0,
                                        &aperclk_lock);
    clks[i2c0_aper] = clk_register_gate(NULL, clk_output_name[i2c0_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 18, 0,
                                        &aperclk_lock);
    clks[i2c1_aper] = clk_register_gate(NULL, clk_output_name[i2c1_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 19, 0,
                                        &aperclk_lock);
    clks[uart0_aper] = clk_register_gate(NULL, clk_output_name[uart0_aper],
                                         clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 20, 0,
                                         &aperclk_lock);
    clks[uart1_aper] = clk_register_gate(NULL, clk_output_name[uart1_aper],
                                         clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 21, 0,
                                         &aperclk_lock);
    clks[gpio_aper] = clk_register_gate(NULL, clk_output_name[gpio_aper],
                                        clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 22, 0,
                                        &aperclk_lock);
    clks[lqspi_aper] = clk_register_gate(NULL, clk_output_name[lqspi_aper],
                                         clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 23, 0,
                                         &aperclk_lock);
    clks[smc_aper] = clk_register_gate(NULL, clk_output_name[smc_aper],
                                       clk_output_name[cpu_1x], 0, SLCR_APER_CLK_CTRL, 24, 0,
                                       &aperclk_lock);

    for (i = 0; i < ARRAY_SIZE(clks); i++) {
        if (IS_ERR(clks[i])) {
            pr_err("Zynq clk %d: register failed with %ld\n",
                   i, PTR_ERR(clks[i]));
            BUG();
        }
    }

    clk_data.clks = clks;
    clk_data.clk_num = ARRAY_SIZE(clks);
    of_clk_add_provider(np, of_clk_src_onecell_get, &clk_data);
}
Esempio n. 13
0
static void __init st_of_clkgena_divmux_setup(struct device_node *np)
{
	const struct of_device_id *match;
	const struct clkgena_divmux_data *data;
	struct clk_onecell_data *clk_data;
	void __iomem *reg;
	const char **parents;
	int num_parents = 0, i;

	match = of_match_node(clkgena_divmux_of_match, np);
	if (WARN_ON(!match))
		return;

	data = match->data;

	reg = clkgen_get_register_base(np);
	if (!reg)
		return;

	parents = clkgen_mux_get_parents(np, &num_parents);
	if (IS_ERR(parents))
		goto err_parents;

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

	clk_data->clk_num = data->num_outputs;
	clk_data->clks = kcalloc(clk_data->clk_num, sizeof(struct clk *),
				 GFP_KERNEL);

	if (!clk_data->clks)
		goto err_alloc_clks;

	for (i = 0; i < clk_data->clk_num; i++) {
		struct clk *clk;
		const char *clk_name;

		if (of_property_read_string_index(np, "clock-output-names",
						  i, &clk_name))
			break;

		/*
		 * If we read an empty clock name then the output is unused
		 */
		if (*clk_name == '\0')
			continue;

		clk = clk_register_genamux(clk_name, parents, num_parents,
					   reg, data, i);

		if (IS_ERR(clk))
			goto err;

		clk_data->clks[i] = clk;
	}

	kfree(parents);

	of_clk_add_provider(np, of_clk_src_onecell_get, clk_data);
	return;
err:
	kfree(clk_data->clks);
err_alloc_clks:
	kfree(clk_data);
err_alloc:
	kfree(parents);
err_parents:
	iounmap(reg);
}