Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3aed68ed authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "regulator: mem-acc-regulator: Add support for updating mem type registers"

parents c9f8344d d59167ed
Loading
Loading
Loading
Loading
+25 −6
Original line number Diff line number Diff line
@@ -18,13 +18,17 @@ Required properties:

Optional properties:
- reg:				Register addresses for acc-sel-l1, acc-sel-l2 control, acc-en,
				MEM ACC eFuse address, acc-l1-custom and acc-l2-custom.
				MEM ACC eFuse address, acc-l1-custom , acc-l2-custom,
				mem-acc-type1, mem-acc-type2, mem-acc-type3, mem-acc-type4,
				mem-acc-type5 and mem-acc-type6.
- reg-names:			Register names. Must be "acc-sel-l1",
				"acc-sel-l2", "acc-en", "efuse_addr",
				"acc-l1-custom", "acc-l2-custom".
				"acc-l1-custom", "acc-l2-custom", "mem-acc-type1",
				"mem-acc-type2", "mem-acc-type3", "mem-acc-type4",
				"mem-acc-type5", "mem-acc-type6".
				A given mem-acc-regulator driver must have "acc-sel-l1" or
				"acc-sel-l2" reg-names property and related register address
				property.
				"acc-sel-l2" or "mem-acc-type*" reg-names property and
				related register address property.
- qcom,acc-en-bit-pos		Array which specifies bit positions in the
				'acc-en' register. Setting these bits forces the
				the acclerator to use the corner value specified
@@ -107,13 +111,24 @@ Optional properties:
				is specified by "acc-l2-custom" reg-property. The length of the array
				should be equal to number of APC corners.
				This property can only be specified if the " qcom,l2-acc-custom-data" is already defined.
- qcom,mem-acc-type1:		Array which specifies the value to be written to the mem acc type1 register for each fuse
				corner, from the lowest fuse corner to the highest fuse corner. The length of the array
				must be equal to the number of APC fuse corners. This property must be present if reg names
				specifies mem-acc-type1.
- qcom,mem-acc-type2:		Same as qcom,mem-acc-type1 except for mem acc type2 register.
- qcom,mem-acc-type3:		Same as qcom,mem-acc-type1 except for mem acc type3 register.
- qcom,mem-acc-type4:		Same as qcom,mem-acc-type1 except for mem acc type4 register.
- qcom,mem-acc-type5:		Same as qcom,mem-acc-type1 except for mem acc type5 register.
- qcom,mem-acc-type6:		Same as qcom,mem-acc-type1 except for mem acc type6 register.

mem_acc_vreg_corner: regulator@fd4aa044 {
	compatible = "qcom,mem-acc-regulator";
	reg = <0xfd4aa048 0x1>, <0xfd4aa044 0x1>, <0xfd4af000 0x1>,
		<0x58000 0x1000>, <0x01942124 0x4>;
		<0x58000 0x1000>, <0x01942124 0x4>, <0xf900d084 1>,
		<0xf900d088 1>, <0xf900d08c 1>, <0xf900d090 1>;
	reg-names = "acc-en", "acc-sel-l1" , "acc-sel-l2",
		"efuse_addr", "acc-l2-custom";
		"efuse_addr", "acc-l2-custom", "mem-acc-type1",
		"mem-acc-type2", "mem-acc-type3", "mem-acc-type4";
	regulator-name = "mem_acc_corner";
	regulator-min-microvolt = <1>;
	regulator-max-microvolt = <3>;
@@ -129,4 +144,8 @@ mem_acc_vreg_corner: regulator@fd4aa044 {
	qcom,override-acc-fuse-sel = <0 52 1 1 0>;
	qcom,override-corner-acc-map = <0 0 1>;
	qcom,overide-l2-acc-custom-data = <0x0 0x0 0x3000>;
	qcom,mem-acc-type1 = <0x02 0x02 0x00>;
	qcom,mem-acc-type2 = <0x02 0x02 0x00>;
	qcom,mem-acc-type3 = <0x02 0x02 0x00>;
	qcom,mem-acc-type4 = <0x02 0x02 0x00>;
};
+75 −3
Original line number Diff line number Diff line
/* Copyright (c) 2014, The Linux Foundation. All rights reserved.
/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
@@ -24,6 +24,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
#include <linux/string.h>
#include <soc/qcom/scm.h>

#define MEM_ACC_DEFAULT_SEL_SIZE	2
@@ -40,6 +41,8 @@ enum {
	MEMORY_MAX,
};

#define MEM_ACC_TYPE_MAX		6

struct mem_acc_regulator {
	struct device		*dev;
	struct regulator_desc	rdesc;
@@ -67,6 +70,9 @@ struct mem_acc_regulator {
	void __iomem		*acc_custom_addr[MEMORY_MAX];
	u32			*acc_custom_data[MEMORY_MAX];

	phys_addr_t		mem_acc_type_addr[MEM_ACC_TYPE_MAX];
	u32			*mem_acc_type_data;

	/* eFuse parameters */
	phys_addr_t		efuse_addr;
	void __iomem		*efuse_base;
@@ -182,6 +188,24 @@ static void __update_acc_sel(struct mem_acc_regulator *mem_acc_vreg,
	writel_relaxed(acc_data, mem_acc_vreg->acc_sel_base[mem_type]);
}

static void __update_acc_type(struct mem_acc_regulator *mem_acc_vreg,
				int corner)
{
	int i, rc;

	for (i = 0; i < MEM_ACC_TYPE_MAX; i++) {
		if (mem_acc_vreg->mem_acc_type_addr[i]) {
			rc = scm_io_write(mem_acc_vreg->mem_acc_type_addr[i],
				mem_acc_vreg->mem_acc_type_data[corner - 1 + i *
				mem_acc_vreg->num_corners]);
			if (rc)
				pr_err("scm_io_write: %pa failure rc:%d\n",
					&(mem_acc_vreg->mem_acc_type_addr[i]),
					rc);
		}
	}
}

static void __update_acc_custom(struct mem_acc_regulator *mem_acc_vreg,
						int corner, int mem_type)
{
@@ -202,6 +226,9 @@ static void update_acc_sel(struct mem_acc_regulator *mem_acc_vreg, int corner)
		if (mem_acc_vreg->mem_acc_custom_supported[i])
			__update_acc_custom(mem_acc_vreg, corner, i);
	}

	if (mem_acc_vreg->mem_acc_type_data)
		__update_acc_type(mem_acc_vreg, corner);
}

static int mem_acc_regulator_set_voltage(struct regulator_dev *rdev,
@@ -544,12 +571,15 @@ static int override_mem_acc_custom_data(struct platform_device *pdev,
	return 0;
}

#define MEM_TYPE_STRING_LEN	20
static int mem_acc_init(struct platform_device *pdev,
		struct mem_acc_regulator *mem_acc_vreg)
{
	struct resource *res;
	int len, rc, i;
	int len, rc, i, j;
	u32 override_acc_fuse_sel[5];
	bool acc_type_present = false;
	char tmps[MEM_TYPE_STRING_LEN];

	res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "acc-en");
	if (!res || !res->start) {
@@ -609,6 +639,18 @@ static int mem_acc_init(struct platform_device *pdev,
		mem_acc_vreg->mem_acc_supported[MEMORY_L2] = true;
	}

	for (i = 0; i < MEM_ACC_TYPE_MAX; i++) {
		snprintf(tmps, MEM_TYPE_STRING_LEN, "mem-acc-type%d", i + 1);
		res = platform_get_resource_byname(pdev, IORESOURCE_MEM, tmps);

		if (!res || !res->start) {
			pr_debug("'%s' resource missing or not used.\n", tmps);
		} else {
			mem_acc_vreg->mem_acc_type_addr[i] = res->start;
			acc_type_present = true;
		}
	}

	rc = populate_acc_data(mem_acc_vreg, "qcom,corner-acc-map",
			&mem_acc_vreg->corner_acc_map,
			&mem_acc_vreg->num_corners);
@@ -624,7 +666,7 @@ static int mem_acc_init(struct platform_device *pdev,
		if (mem_acc_vreg->mem_acc_supported[i])
			break;
	}
	if (i == MEMORY_MAX) {
	if (i == MEMORY_MAX && !acc_type_present) {
		pr_err("No mem-acc configuration specified\n");
		return -EINVAL;
	}
@@ -694,6 +736,36 @@ static int mem_acc_init(struct platform_device *pdev,
		}
	}

	if (acc_type_present) {
		mem_acc_vreg->mem_acc_type_data = devm_kzalloc(
			mem_acc_vreg->dev, mem_acc_vreg->num_corners *
			MEM_ACC_TYPE_MAX * sizeof(u32), GFP_KERNEL);

		if (!mem_acc_vreg->mem_acc_type_data) {
			pr_err("Unable to allocate memory for mem_acc_type\n");
			return -ENOMEM;
		}

		for (i = 0; i < MEM_ACC_TYPE_MAX; i++) {
			if (mem_acc_vreg->mem_acc_type_addr[i]) {
				snprintf(tmps, MEM_TYPE_STRING_LEN,
					"qcom,mem-acc-type%d", i + 1);

				j = i * mem_acc_vreg->num_corners;
				rc = of_property_read_u32_array(
					mem_acc_vreg->dev->of_node,
					tmps,
					&mem_acc_vreg->mem_acc_type_data[j],
					mem_acc_vreg->num_corners);
				if (rc) {
					pr_err("Unable to get property %s rc=%d\n",
						tmps, rc);
					return rc;
				}
			}
		}
	}

	return 0;
}