diff options
author | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2015-01-30 17:42:05 +0000 |
---|---|---|
committer | Srinivas Kandagatla <srinivas.kandagatla@linaro.org> | 2015-01-30 17:42:05 +0000 |
commit | e37b32df53fb60634cc189f14b4bc21be517ce30 (patch) | |
tree | 4331fec8b5a115c70f79d9534c960c406e0fb5d0 /drivers/soc | |
parent | 35d233256a2c4359ec474ae64d4332e436899100 (diff) | |
parent | 279fe9083762118a8dd87e41b8ec5149996b5a57 (diff) |
Merge branch 'tracking-qcomlt-tsens' into integration-linux-qcomltqcomlt-v3.19-rc6-30012015
* tracking-qcomlt-tsens:
thermal: qcom: Add 8960 thermal sensor support
WIP: Add wrappers for qfprom access via syscon
WIP: mfd: syscon: Add register stride to DT bindings.
Conflicts:
drivers/soc/qcom/Kconfig
drivers/soc/qcom/Makefile
Diffstat (limited to 'drivers/soc')
-rw-r--r-- | drivers/soc/qcom/Kconfig | 7 | ||||
-rw-r--r-- | drivers/soc/qcom/Makefile | 1 | ||||
-rw-r--r-- | drivers/soc/qcom/qfprom.c | 134 |
3 files changed, 142 insertions, 0 deletions
diff --git a/drivers/soc/qcom/Kconfig b/drivers/soc/qcom/Kconfig index 012fb37b3ba9..389ec3ea7190 100644 --- a/drivers/soc/qcom/Kconfig +++ b/drivers/soc/qcom/Kconfig @@ -19,3 +19,10 @@ config QCOM_PM QCOM Platform specific power driver to manage cores and L2 low power modes. It interface with various system drivers to put the cores in low power modes. + +config QCOM_QFPROM + tristate "QCOM QFPROM Interface" + depends on ARCH_QCOM && OF + help + Say y here to enable QFPROM support. The QFPROM provides access + functions for QFPROM data to rest of the drivers via syscon wrappers. diff --git a/drivers/soc/qcom/Makefile b/drivers/soc/qcom/Makefile index 4d4ff4a09b7d..54249f557778 100644 --- a/drivers/soc/qcom/Makefile +++ b/drivers/soc/qcom/Makefile @@ -2,3 +2,4 @@ obj-$(CONFIG_QCOM_GSBI) += qcom_gsbi.o obj-$(CONFIG_QCOM_PM) += spm.o CFLAGS_scm.o :=$(call as-instr,.arch_extension sec,-DREQUIRES_SEC=1) obj-$(CONFIG_QCOM_SCM) += scm.o scm-boot.o scm-pas.o +obj-$(CONFIG_QCOM_QFPROM) += qfprom.o diff --git a/drivers/soc/qcom/qfprom.c b/drivers/soc/qcom/qfprom.c new file mode 100644 index 000000000000..d00ed25235d7 --- /dev/null +++ b/drivers/soc/qcom/qfprom.c @@ -0,0 +1,134 @@ +#include <linux/err.h> +#include <linux/of.h> +#include <linux/device.h> +#include <linux/regmap.h> +#include <linux/mfd/syscon.h> +#include <linux/soc/qcom/qfprom.h> +#include <linux/slab.h> + +#define QFPROM_MAX_ARGS 2 + +static char *__qfprom_get_data(struct device *dev, + bool devm, int idx, int *len) +{ + struct device_node *syscon_np, *np = dev->of_node; + struct regmap *rm; + struct of_phandle_args args; + int rc, stride = 4; + u32 offset, size; + char *data; + + if (!np) + return ERR_PTR(-EINVAL); + + rc = of_parse_phandle_with_fixed_args(np, "qcom,qfprom", + QFPROM_MAX_ARGS, idx, &args); + if (rc) + return ERR_PTR(rc); + + syscon_np = args.np; + + of_property_read_u32(syscon_np, "stride", &stride); + + if (stride >= 4) + stride = 4; + + if (args.args_count < QFPROM_MAX_ARGS) { + dev_err(dev, "Insufficient qfprom arguments %d\n", + args.args_count); + return ERR_PTR(-EINVAL); + } + + rm = syscon_node_to_regmap(syscon_np); + if (IS_ERR(rm)) + return ERR_CAST(rm); + + offset = args.args[0]; + size = args.args[1]; + + of_node_put(syscon_np); + + if (devm) + data = devm_kzalloc(dev, size, GFP_KERNEL | GFP_ATOMIC); + else + data = kzalloc(size, GFP_KERNEL | GFP_ATOMIC); + + if (!data) + return ERR_PTR(-ENOMEM); + + rc = regmap_bulk_read(rm, offset, data, size/stride); + if (rc < 0) { + if (devm) + devm_kfree(dev, data); + else + kfree(data); + + return ERR_PTR(rc); + } + + *len = size; + + return data; +} + +static char *__qfprom_get_data_byname(struct device *dev, + bool devm, const char *name, int *len) +{ + int index = 0; + + if (name) + index = of_property_match_string(dev->of_node, + "qcom,qfprom-names", name); + + return __qfprom_get_data(dev, devm, index, len); +} + +char *devm_qfprom_get_data_byname(struct device *dev, + const char *name, int *len) +{ + return __qfprom_get_data_byname(dev, true, name, len); +} +EXPORT_SYMBOL_GPL(devm_qfprom_get_data_byname); + +char *devm_qfprom_get_data(struct device *dev, + int index, int *len) +{ + return __qfprom_get_data(dev, true, index, len); +} +EXPORT_SYMBOL_GPL(devm_qfprom_get_data); + +/** + * qfprom_get_data_byname(): Reads qfprom data by name + * + * @dev: device which is requesting qfprom data + * @index: name of qfprom resources specified "qcom,qfprom-names" DT property. + * @len: length of data read from qfprom. + * + * The return value will be an ERR_PTR() on error or a valid pointer + * to a data buffer. The buffer should be freed by the user once its + * finished working with it kfree. + **/ +char *qfprom_get_data_byname(struct device *dev, + const char *name, int *len) +{ + return __qfprom_get_data_byname(dev, false, name, len); +} +EXPORT_SYMBOL_GPL(qfprom_get_data_byname); + +/** + * qfprom_get_data(): Reads qfprom data from the index + * + * @dev: device which is requesting qfprom data + * @index: index into qfprom resources specified "qcom,qfprom" DT property. + * @len: length of data read from qfprom. + * + * The return value will be an ERR_PTR() on error or a valid pointer + * to a data buffer. The buffer should be freed by the user once its + * finished working with it kfree. + **/ +char *qfprom_get_data(struct device *dev, + int index, int *len) +{ + return __qfprom_get_data(dev, false, index, len); +} +EXPORT_SYMBOL_GPL(qfprom_get_data); |