Commit d920940be699a866c6853971d5589d6249bce6a4

Authored by Ravikumar Kattekola
Committed by Jacob Stiffler
1 parent 053aa6ec56

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 <rk@ti.com>

Showing 6 changed files with 275 additions and 0 deletions Side-by-side Diff

Documentation/devicetree/bindings/power/coproc/ti-coproc.txt
  1 +Texas Instruments co-processor driver
  2 +
  3 +A co-processor device is a non-cpu processor found on an SoC.
  4 +
  5 +This document describes the clock and voltage configuration
  6 +used by co-processors/devices typically found on Texas Instrument SoCs.
  7 +
  8 +Required properties
  9 +- compatible: should be
  10 + "ti,coproc"
  11 +- clocks: <functional clock>, <dpll clock>
  12 + dpll clock is optional
  13 +- clock-names: "fclk", "dpll"
  14 + if you change names here, go chnage the driver too
  15 +- clock-target-frequency: Mention your target frequency here
  16 +- operating-points: all OPPs applicable for this device/coprocessor
  17 +- coproc-voltdm: phandle of the Voltage domain associated with this device/coproc
  18 +- voltage-tolerance: Specify a voltage tolerance allowed for this voltage domain
  19 +as per datamanual limits
  20 +
  21 +Example:
  22 +iva_coproc {
  23 + compatible = "ti,coproc";
  24 + clocks = <&dpll_iva_m2_ck>, <&dpll_iva_ck>;
  25 + clock-names = "fclk", "dpll";
  26 + clock-target-frequency = <532000000>;
  27 + operating-points = <
  28 + 388200 1055000
  29 + 430000 1150000
  30 + 532000 1250000
  31 + >;
  32 + coproc-voltdm = <&voltdm_ivahd>;
  33 + voltage-tolerance = <1>;
  34 +};
drivers/power/Kconfig
... ... @@ -395,4 +395,5 @@
395 395  
396 396 source "drivers/power/avs/Kconfig"
397 397 source "drivers/power/voltdm/Kconfig"
  398 +source "drivers/power/coproc/Kconfig"
drivers/power/Makefile
... ... @@ -59,4 +59,5 @@
59 59 obj-$(CONFIG_CHARGER_TPS65090) += tps65090-charger.o
60 60 obj-$(CONFIG_POWER_RESET) += reset/
61 61 obj-$(CONFIG_VOLTAGE_DOMAIN) += voltdm/
  62 +obj-$(CONFIG_TI_COPROC) += coproc/
drivers/power/coproc/Kconfig
  1 +config TI_COPROC
  2 + tristate "TI Co-processor driversupport"
  3 + depends on VOLTAGE_DOMAIN_OMAP
  4 + help
  5 + TI Coprocessor driver helps initialize a coprocessor to
  6 + a particular Operating performance point.
drivers/power/coproc/Makefile
  1 +#Texas Instruments co-processor init driver
  2 +obj-${CONFIG_TI_COPROC} += ti-coproc.o
drivers/power/coproc/ti-coproc.c
  1 +/*
  2 + * OMAP SoC COPROC driver
  3 + *
  4 + * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
  5 + * Carlos Hernandez <ceh@ti.com>
  6 + * Nishanth Menon <nm@ti.com>
  7 + * Ravikumar Kattekola <rk@ti.com>
  8 + * This program is free software; you can redistribute it and/or modify
  9 + * it under the terms of the GNU General Public License version 2 as
  10 + * published by the Free Software Foundation.
  11 + *
  12 + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
  13 + * kind, whether express or implied; without even the implied warranty
  14 + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15 + * GNU General Public License for more details.
  16 + */
  17 +#include <linux/io.h>
  18 +#include <linux/slab.h>
  19 +#include <linux/mutex.h>
  20 +#include <linux/suspend.h>
  21 +#include <linux/pm_opp.h>
  22 +#include <linux/of.h>
  23 +#include <linux/platform_device.h>
  24 +#include <linux/regulator/consumer.h>
  25 +#include <linux/module.h>
  26 +#include <linux/clk.h>
  27 +#include <linux/pm_voltage_domain.h>
  28 +
  29 +/**
  30 + * struct coproc_data - Co processor private data
  31 + * @profile: profile specific for this device
  32 + * @dev: device pointer
  33 + * @: for this device
  34 + * @stat: my current statistics
  35 + * @dev_clk: my device clk
  36 + * @dpll_clk: my dpll clk
  37 + * @nb: my notifier block
  38 + */
  39 +struct coproc_data {
  40 + struct device *dev;
  41 + struct clk *dev_clk;
  42 + struct clk *dpll_clk;
  43 + struct notifier_block *clk_nb;
  44 +};
  45 +
  46 +/**
  47 + * DOC:
  48 + * clock-names should be defined in dts file, e.g.
  49 + * coproc {
  50 + *
  51 + * compatible = "ti,coproc";
  52 + * clocks = <&dpll_iva_m2_ck>, <&dpll_iva_ck>;
  53 + * clock-names = "fclk", "dpll";
  54 + * clock-target-frequency = <532000000>;
  55 + * operating-points = <
  56 + * 388200 1055000
  57 + * 500000 1150000
  58 + * 532000 1250000
  59 + * >;
  60 + * coproc-voltdm = <&voltdm_ivahd>;
  61 + * voltage-tolerance = <1>;
  62 + *
  63 + * };
  64 + */
  65 +#define DEV_CLK_NAME "fclk"
  66 +#define DPLL_CLK_NAME "dpll"
  67 +
  68 +static int coproc_probe(struct platform_device *pdev)
  69 +{
  70 + struct coproc_data *d;
  71 + unsigned int voltage_latency;
  72 + u32 target_freq = 0;
  73 + int err = 0;
  74 + struct device *dev = &pdev->dev;
  75 + struct device_node *np = of_node_get(dev->of_node);
  76 + bool noset_dpll_as_rate;
  77 +
  78 + dev_info(dev, "probe\n");
  79 +
  80 + of_property_read_u32(np, "clock-target-frequency", &target_freq);
  81 + if (!target_freq) {
  82 + dev_err(dev, "%s: Invalid/no target frequency found in dt.\n",
  83 + __func__);
  84 + return -EINVAL;
  85 + }
  86 +
  87 + noset_dpll_as_rate = of_property_read_bool(np, "noset-dpll-rate");
  88 +
  89 + d = devm_kzalloc(dev, sizeof(*d), GFP_KERNEL);
  90 + if (d == NULL) {
  91 + dev_err(dev, "%s: Cannot allocate memory.\n", __func__);
  92 + err = -ENOMEM;
  93 + goto out;
  94 + }
  95 + platform_set_drvdata(pdev, d);
  96 +
  97 + d->dpll_clk = devm_clk_get(dev, DPLL_CLK_NAME);
  98 + if (IS_ERR(d->dpll_clk)) {
  99 + err = PTR_ERR(d->dpll_clk);
  100 + dev_err(dev, "%s: Cannot get dpll clk(%d).\n", __func__, err);
  101 + d->dpll_clk = NULL;
  102 + }
  103 +
  104 + d->dev_clk = devm_clk_get(dev, DEV_CLK_NAME);
  105 + if (IS_ERR(d->dev_clk)) {
  106 + err = PTR_ERR(d->dpll_clk);
  107 + dev_err(dev, "%s: Cannot get func clk(%d).\n", __func__, err);
  108 + goto out;
  109 + }
  110 +
  111 + if (noset_dpll_as_rate)
  112 + d->dpll_clk = NULL;
  113 +
  114 + err = of_init_opp_table(dev);
  115 + if (err) {
  116 + dev_err(dev, "%s: Cannot initialize opp table(%d).\n", __func__,
  117 + err);
  118 + goto out;
  119 + }
  120 + d->dev = dev;
  121 +
  122 + /* Register voltage domain notifier */
  123 + d->clk_nb = of_pm_voltdm_notifier_register(dev, np, d->dev_clk,
  124 + "coproc",
  125 + &voltage_latency);
  126 + if (IS_ERR(d->clk_nb)) {
  127 + err = PTR_ERR(d->clk_nb);
  128 + /* defer probe if regulator is not yet registered */
  129 + if (err == -EPROBE_DEFER) {
  130 + dev_err(dev,
  131 + "coproc clock notifier not ready, retry\n");
  132 + } else {
  133 + dev_err(dev,
  134 + "Failed to register coproc clk notifier: %d\n",
  135 + err);
  136 + }
  137 + goto out;
  138 + }
  139 +
  140 + if (target_freq) {
  141 + if (d->dpll_clk) {
  142 + err = clk_set_rate(d->dpll_clk, target_freq);
  143 + if (err) {
  144 + dev_err(dev, "%s: Cannot set dpll clock rate(%d).\n",
  145 + __func__, err);
  146 + goto out;
  147 + }
  148 + }
  149 +
  150 + err = clk_set_rate(d->dev_clk, target_freq);
  151 + if (err) {
  152 + dev_err(dev, "%s: Cannot set func clock rate(%d).\n",
  153 + __func__, err);
  154 + goto out;
  155 + }
  156 + }
  157 +
  158 + /* All good.. */
  159 + goto out;
  160 +
  161 +out:
  162 + dev_info(dev, "%s result=%d", __func__, err);
  163 + return err;
  164 +}
  165 +
  166 +static int coproc_remove(struct platform_device *pdev)
  167 +{
  168 + struct coproc_data *d = platform_get_drvdata(pdev);
  169 + struct device *dev = &pdev->dev;
  170 +
  171 + dev_info(dev, "remove\n");
  172 +
  173 + of_pm_voltdm_notifier_unregister(d->clk_nb);
  174 +
  175 + dev_info(dev, "%s Removed\n", __func__);
  176 + return 0;
  177 +}
  178 +
  179 +/**
  180 + * coproc_suspend() - dummy hook for suspend
  181 + * @dev: device pointer
  182 + *
  183 + * Return: 0
  184 + */
  185 +static int coproc_suspend(struct device *dev)
  186 +{
  187 + dev_info(dev, "suspend\n");
  188 + return 0;
  189 +}
  190 +
  191 +/**
  192 + * coproc_resume() - dummy hook for resume
  193 + * @dev: device pointer
  194 + *
  195 + * Return: 0
  196 + */
  197 +static int coproc_resume(struct device *dev)
  198 +{
  199 + dev_info(dev, "resume\n");
  200 + return 0;
  201 +}
  202 +
  203 +/* Device power management hooks */
  204 +static SIMPLE_DEV_PM_OPS(coproc_pm,
  205 + coproc_suspend,
  206 + coproc_resume);
  207 +
  208 +static struct of_device_id of_coproc_match[] = {
  209 + {.compatible = "ti,coproc"},
  210 + {},
  211 +};
  212 +
  213 +MODULE_DEVICE_TABLE(of, of_coproc_match);
  214 +
  215 +static struct platform_driver coproc_driver = {
  216 + .probe = coproc_probe,
  217 + .remove = coproc_remove,
  218 + .driver = {
  219 + .name = "coproc",
  220 + .owner = THIS_MODULE,
  221 + .of_match_table = of_match_ptr(of_coproc_match),
  222 + .pm = &coproc_pm,
  223 + },
  224 +};
  225 +module_platform_driver(coproc_driver);
  226 +
  227 +MODULE_LICENSE("GPL v2");
  228 +MODULE_DESCRIPTION("OMAP Co-processor Driver");
  229 +MODULE_AUTHOR("Texas Instruments Inc.");