From d920940be699a866c6853971d5589d6249bce6a4 Mon Sep 17 00:00:00 2001 From: Ravikumar Kattekola Date: Sun, 11 Jan 2015 23:04:34 +0530 Subject: [PATCH] drivers: power: Introduce TI coprocessor driver All the coprocessors may not be used in all the system usecase scenarios, so we need a driver that can initialize the coprocessors based on the current system usecase. In a scenario where the user knows ahead what's the target OPP for a usecase and which doesnt change during runtime, using devfreq would be an overkill. Introduce a simple driver to configure the initial Operating frequency an dvoltage (OPP) for co processors in a SoC. TI co-processor driver makes use of voltage domain manager for handling the clock frequency changes and corresponding voltage handling thus it can still work seamlessly in a ganged rail scenario where the voltage rails of more than one coprocssor are ganged up. Change-Id: If8c4afba833cf972e080f81c9e02f3126703b96c Signed-off-by: Ravikumar Kattekola --- .../devicetree/bindings/power/coproc/ti-coproc.txt | 35 ++++ drivers/power/Kconfig | 1 + drivers/power/Makefile | 1 + drivers/power/coproc/Kconfig | 7 + drivers/power/coproc/Makefile | 2 + drivers/power/coproc/ti-coproc.c | 229 +++++++++++++++++++++ 6 files changed, 275 insertions(+) create mode 100644 Documentation/devicetree/bindings/power/coproc/ti-coproc.txt create mode 100644 drivers/power/coproc/Kconfig create mode 100644 drivers/power/coproc/Makefile create mode 100644 drivers/power/coproc/ti-coproc.c diff --git a/Documentation/devicetree/bindings/power/coproc/ti-coproc.txt b/Documentation/devicetree/bindings/power/coproc/ti-coproc.txt new file mode 100644 index 0000000..d60c1f2 --- /dev/null +++ b/Documentation/devicetree/bindings/power/coproc/ti-coproc.txt @@ -0,0 +1,35 @@ +Texas Instruments co-processor driver + +A co-processor device is a non-cpu processor found on an SoC. + +This document describes the clock and voltage configuration +used by co-processors/devices typically found on Texas Instrument SoCs. + +Required properties +- compatible: should be + "ti,coproc" +- clocks: , + dpll clock is optional +- clock-names: "fclk", "dpll" + if you change names here, go chnage the driver too +- clock-target-frequency: Mention your target frequency here +- operating-points: all OPPs applicable for this device/coprocessor +- coproc-voltdm: phandle of the Voltage domain associated with this device/coproc +- voltage-tolerance: Specify a voltage tolerance allowed for this voltage domain +as per datamanual limits + +Example: +iva_coproc { + compatible = "ti,coproc"; + clocks = <&dpll_iva_m2_ck>, <&dpll_iva_ck>; + clock-names = "fclk", "dpll"; + clock-target-frequency = <532000000>; + operating-points = < + 388200 1055000 + 430000 1150000 + 532000 1250000 + >; + coproc-voltdm = <&voltdm_ivahd>; + voltage-tolerance = <1>; +}; + diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig index 5c4fe16..8b07dc1 100644 --- a/drivers/power/Kconfig +++ b/drivers/power/Kconfig @@ -395,3 +395,4 @@ endif # POWER_SUPPLY source "drivers/power/avs/Kconfig" source "drivers/power/voltdm/Kconfig" +source "drivers/power/coproc/Kconfig" diff --git a/drivers/power/Makefile b/drivers/power/Makefile index 3d47072..a76fa2a 100644 --- a/drivers/power/Makefile +++ b/drivers/power/Makefile @@ -59,3 +59,4 @@ obj-$(CONFIG_CHARGER_SMB347) += smb347-charger.o obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o obj-$(CONFIG_POWER_RESET) += reset/ obj-$(CONFIG_VOLTAGE_DOMAIN) += voltdm/ +obj-$(CONFIG_TI_COPROC) += coproc/ diff --git a/drivers/power/coproc/Kconfig b/drivers/power/coproc/Kconfig new file mode 100644 index 0000000..ec0e307 --- /dev/null +++ b/drivers/power/coproc/Kconfig @@ -0,0 +1,7 @@ +config TI_COPROC + tristate "TI Co-processor driversupport" + depends on VOLTAGE_DOMAIN_OMAP + help + TI Coprocessor driver helps initialize a coprocessor to + a particular Operating performance point. + diff --git a/drivers/power/coproc/Makefile b/drivers/power/coproc/Makefile new file mode 100644 index 0000000..5e393a5 --- /dev/null +++ b/drivers/power/coproc/Makefile @@ -0,0 +1,2 @@ +#Texas Instruments co-processor init driver +obj-${CONFIG_TI_COPROC} += ti-coproc.o diff --git a/drivers/power/coproc/ti-coproc.c b/drivers/power/coproc/ti-coproc.c new file mode 100644 index 0000000..3795d36 --- /dev/null +++ b/drivers/power/coproc/ti-coproc.c @@ -0,0 +1,229 @@ +/* + * OMAP SoC COPROC driver + * + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/ + * Carlos Hernandez + * Nishanth Menon + * Ravikumar Kattekola + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * This program is distributed "as is" WITHOUT ANY WARRANTY of any + * kind, whether express or implied; without even the implied warranty + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** + * struct coproc_data - Co processor private data + * @profile: profile specific for this device + * @dev: device pointer + * @: for this device + * @stat: my current statistics + * @dev_clk: my device clk + * @dpll_clk: my dpll clk + * @nb: my notifier block + */ +struct coproc_data { + struct device *dev; + struct clk *dev_clk; + struct clk *dpll_clk; + struct notifier_block *clk_nb; +}; + +/** + * DOC: + * clock-names should be defined in dts file, e.g. + * coproc { + * + * compatible = "ti,coproc"; + * clocks = <&dpll_iva_m2_ck>, <&dpll_iva_ck>; + * clock-names = "fclk", "dpll"; + * clock-target-frequency = <532000000>; + * operating-points = < + * 388200 1055000 + * 500000 1150000 + * 532000 1250000 + * >; + * coproc-voltdm = <&voltdm_ivahd>; + * voltage-tolerance = <1>; + * + * }; + */ +#define DEV_CLK_NAME "fclk" +#define DPLL_CLK_NAME "dpll" + +static int coproc_probe(struct platform_device *pdev) +{ + struct coproc_data *d; + unsigned int voltage_latency; + u32 target_freq = 0; + int err = 0; + struct device *dev = &pdev->dev; + struct device_node *np = of_node_get(dev->of_node); + bool noset_dpll_as_rate; + + dev_info(dev, "probe\n"); + + of_property_read_u32(np, "clock-target-frequency", &target_freq); + if (!target_freq) { + dev_err(dev, "%s: Invalid/no target frequency found in dt.\n", + __func__); + return -EINVAL; + } + + noset_dpll_as_rate = of_property_read_bool(np, "noset-dpll-rate"); + + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL); + if (d == NULL) { + dev_err(dev, "%s: Cannot allocate memory.\n", __func__); + err = -ENOMEM; + goto out; + } + platform_set_drvdata(pdev, d); + + d->dpll_clk = devm_clk_get(dev, DPLL_CLK_NAME); + if (IS_ERR(d->dpll_clk)) { + err = PTR_ERR(d->dpll_clk); + dev_err(dev, "%s: Cannot get dpll clk(%d).\n", __func__, err); + d->dpll_clk = NULL; + } + + d->dev_clk = devm_clk_get(dev, DEV_CLK_NAME); + if (IS_ERR(d->dev_clk)) { + err = PTR_ERR(d->dpll_clk); + dev_err(dev, "%s: Cannot get func clk(%d).\n", __func__, err); + goto out; + } + + if (noset_dpll_as_rate) + d->dpll_clk = NULL; + + err = of_init_opp_table(dev); + if (err) { + dev_err(dev, "%s: Cannot initialize opp table(%d).\n", __func__, + err); + goto out; + } + d->dev = dev; + + /* Register voltage domain notifier */ + d->clk_nb = of_pm_voltdm_notifier_register(dev, np, d->dev_clk, + "coproc", + &voltage_latency); + if (IS_ERR(d->clk_nb)) { + err = PTR_ERR(d->clk_nb); + /* defer probe if regulator is not yet registered */ + if (err == -EPROBE_DEFER) { + dev_err(dev, + "coproc clock notifier not ready, retry\n"); + } else { + dev_err(dev, + "Failed to register coproc clk notifier: %d\n", + err); + } + goto out; + } + + if (target_freq) { + if (d->dpll_clk) { + err = clk_set_rate(d->dpll_clk, target_freq); + if (err) { + dev_err(dev, "%s: Cannot set dpll clock rate(%d).\n", + __func__, err); + goto out; + } + } + + err = clk_set_rate(d->dev_clk, target_freq); + if (err) { + dev_err(dev, "%s: Cannot set func clock rate(%d).\n", + __func__, err); + goto out; + } + } + + /* All good.. */ + goto out; + +out: + dev_info(dev, "%s result=%d", __func__, err); + return err; +} + +static int coproc_remove(struct platform_device *pdev) +{ + struct coproc_data *d = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + + dev_info(dev, "remove\n"); + + of_pm_voltdm_notifier_unregister(d->clk_nb); + + dev_info(dev, "%s Removed\n", __func__); + return 0; +} + +/** + * coproc_suspend() - dummy hook for suspend + * @dev: device pointer + * + * Return: 0 + */ +static int coproc_suspend(struct device *dev) +{ + dev_info(dev, "suspend\n"); + return 0; +} + +/** + * coproc_resume() - dummy hook for resume + * @dev: device pointer + * + * Return: 0 + */ +static int coproc_resume(struct device *dev) +{ + dev_info(dev, "resume\n"); + return 0; +} + +/* Device power management hooks */ +static SIMPLE_DEV_PM_OPS(coproc_pm, + coproc_suspend, + coproc_resume); + +static struct of_device_id of_coproc_match[] = { + {.compatible = "ti,coproc"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, of_coproc_match); + +static struct platform_driver coproc_driver = { + .probe = coproc_probe, + .remove = coproc_remove, + .driver = { + .name = "coproc", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(of_coproc_match), + .pm = &coproc_pm, + }, +}; +module_platform_driver(coproc_driver); + +MODULE_LICENSE("GPL v2"); +MODULE_DESCRIPTION("OMAP Co-processor Driver"); +MODULE_AUTHOR("Texas Instruments Inc."); -- 1.9.1