@@ -8,7 +8,6 @@ the fast CPU cluster. It consists of a free-running voltage controlled
oscillator connected to the CPU voltage rail (VDD_CPU), and a closed loop
control module that will automatically adjust the VDD_CPU voltage by
communicating with an off-chip PMIC either via an I2C bus or via PWM signals.
-Currently only the I2C mode is supported by these bindings.
Required properties:
- compatible : should be one of following:
@@ -36,6 +35,10 @@ Required properties:
hardware will start controlling. The regulator will be queried for
the I2C register, control values and supported voltages.
+Optional properties:
+- nvidia,pwm-to-pmic: Specify DFLL PMU interface as PWM. If the property
+ is not defined, default PMU interface is I2C.
+
Reguired properties for build voltage table:
- nvidia,align-step-uv: Step uV of regulator for CPU voltage rail. This
value will be applied when building frequency-voltage table to ensure
@@ -58,6 +61,9 @@ Optional properties for the control loop parameters:
Required properties for I2C mode:
- nvidia,i2c-fs-rate: I2C transfer rate, if using full speed mode.
+Required properties for PWM mode:
+- nvidia,init-uv: Initialized CPU voltage before DFLL is not ready yet.
+
Example:
clock@0,70110000 {
@@ -53,6 +53,7 @@
#include <linux/regulator/consumer.h>
#include <linux/reset.h>
#include <linux/seq_file.h>
+#include <soc/tegra/pwm-tegra-dfll.h>
#include "clk-dfll.h"
@@ -242,6 +243,11 @@ enum dfll_tune_range {
DFLL_TUNE_LOW = 1,
};
+enum tegra_dfll_pmu_if {
+ TEGRA_DFLL_PMU_I2C = 0,
+ TEGRA_DFLL_PMU_PWM = 1,
+};
+
/**
* struct dfll_rate_req - target DFLL rate request data
* @rate: target frequency, after the postscaling
@@ -293,6 +299,7 @@ struct tegra_dfll {
u32 ci;
u32 cg;
bool cg_scale;
+ u32 reg_init_uV;
/* I2C interface parameters */
u32 i2c_fs_rate;
@@ -300,9 +307,12 @@ struct tegra_dfll {
u32 i2c_slave_addr;
/* i2c_lut array entries are regulator framework selectors */
- unsigned i2c_lut[MAX_DFLL_VOLTAGES];
- int i2c_lut_size;
+ unsigned lut[MAX_DFLL_VOLTAGES];
+ int lut_size;
u8 lut_min, lut_max, lut_safe;
+
+ /* PWM interface */
+ enum tegra_dfll_pmu_if pmu_if;
};
#define clk_hw_to_dfll(_hw) container_of(_hw, struct tegra_dfll, dfll_clk_hw)
@@ -326,7 +336,6 @@ static inline u32 dfll_readl(struct tegra_dfll *td, u32 offs)
static inline void dfll_writel(struct tegra_dfll *td, u32 val, u32 offs)
{
- WARN_ON(offs >= DFLL_I2C_CFG);
__raw_writel(val, td->base + offs);
}
@@ -538,7 +547,7 @@ static void dfll_load_i2c_lut(struct tegra_dfll *td)
lut_index = i;
val = regulator_list_hardware_vsel(td->vdd_reg,
- td->i2c_lut[lut_index]);
+ td->lut[lut_index]);
__raw_writel(val, td->lut_base + i * 4);
}
@@ -581,36 +590,135 @@ static void dfll_init_i2c_if(struct tegra_dfll *td)
dfll_i2c_wmb(td);
}
+/*
+ * DFLL-to-PWM controller interface
+ */
+
/**
- * dfll_init_out_if - prepare DFLL-to-PMIC interface
+ * dfll_set_force_output_value - set fixed value for force output
* @td: DFLL instance
+ * @out_val: value to force output
*
- * During DFLL driver initialization or resume from context loss,
- * disable the I2C command output to the PMIC, set safe voltage and
- * output limits, and disable and clear limit interrupts.
+ * Set the fixec value for force output, DFLL will output this value when
+ * force output is enabled.
*/
-static void dfll_init_out_if(struct tegra_dfll *td)
+static u32 dfll_set_force_output_value(struct tegra_dfll *td, u8 out_val)
+{
+ u32 val = dfll_readl(td, DFLL_OUTPUT_FORCE);
+
+ val |= (val & DFLL_OUTPUT_FORCE_ENABLE) | (out_val & OUT_MASK);
+ dfll_writel(td, val, DFLL_OUTPUT_FORCE);
+ dfll_wmb(td);
+
+ return dfll_readl(td, DFLL_OUTPUT_FORCE);
+}
+
+/**
+ * dfll_set_force_output_enabled - enable/disable force output
+ * @td: DFLL instance
+ * @enable: whether to enable or disable the force output
+ *
+ * Set the enable control for fouce output with fixed value.
+ */
+static void dfll_set_force_output_enabled(struct tegra_dfll *td, bool enable)
+{
+ u32 val = dfll_readl(td, DFLL_OUTPUT_FORCE);
+
+ if (enable)
+ val |= DFLL_OUTPUT_FORCE_ENABLE;
+ else
+ val &= ~DFLL_OUTPUT_FORCE_ENABLE;
+
+ dfll_writel(td, val, DFLL_OUTPUT_FORCE);
+ dfll_wmb(td);
+}
+
+/**
+ * dfll_i2c_set_output_enabled - enable/disable I2C PMIC voltage requests
+ * @td: DFLL instance
+ * @enable: whether to enable or disable the I2C voltage requests
+ *
+ * Set the master enable control for I2C control value updates. If disabled,
+ * then I2C control messages are inhibited, regardless of the DFLL mode.
+ */
+static int dfll_force_output(struct tegra_dfll *td, unsigned int out_sel)
{
u32 val;
- td->lut_min = 0;
- td->lut_max = td->i2c_lut_size - 1;
- td->lut_safe = td->lut_min + 1;
+ if (out_sel > OUT_MASK)
+ return -EINVAL;
- dfll_i2c_writel(td, 0, DFLL_OUTPUT_CFG);
- val = (td->lut_safe << DFLL_OUTPUT_CFG_SAFE_SHIFT) |
- (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) |
- (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT);
- dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG);
- dfll_i2c_wmb(td);
+ val = dfll_set_force_output_value(td, out_sel);
+ if ((td->mode < DFLL_CLOSED_LOOP) &&
+ !(val & DFLL_OUTPUT_FORCE_ENABLE)) {
+ dfll_set_force_output_enabled(td, true);
+ }
- dfll_writel(td, 0, DFLL_OUTPUT_FORCE);
- dfll_i2c_writel(td, 0, DFLL_INTR_EN);
- dfll_i2c_writel(td, DFLL_INTR_MAX_MASK | DFLL_INTR_MIN_MASK,
- DFLL_INTR_STS);
+ return 0;
+}
+
+/**
+ * dfll_init_out_if - prepare DFLL-to-PMIC interface
+ * @td: DFLL instance
+ *
+ * During DFLL driver initialization or resume from context loss,
+ * it needs to set safe voltage and output limits, and disable and
+ * clear limit interrupts. For PWM interface, it needs to set
+ * initial voltage for force output to avoid CPU voltage glitch
+ * during DFLL is from open to closed loop transition.
+ */
+static void dfll_init_out_if(struct tegra_dfll *td)
+{
+ u32 val = 0;
- dfll_load_i2c_lut(td);
- dfll_init_i2c_if(td);
+ if (td->pmu_if == TEGRA_DFLL_PMU_PWM) {
+ int vinit = td->reg_init_uV;
+ int vstep = td->soc->alignment;
+ int vmin = regulator_list_voltage(td->vdd_reg, 0);
+
+ td->lut_min = td->lut[0];
+ td->lut_max = td->lut[td->lut_size - 1];
+ td->lut_safe = td->lut_min + 1;
+
+ val = dfll_readl(td, DFLL_OUTPUT_CFG);
+ val |= (td->lut_safe << DFLL_OUTPUT_CFG_SAFE_SHIFT) |
+ (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) |
+ (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT);
+ dfll_writel(td, val, DFLL_OUTPUT_CFG);
+ dfll_wmb(td);
+
+ dfll_writel(td, 0, DFLL_OUTPUT_FORCE);
+ dfll_writel(td, 0, DFLL_INTR_EN);
+ dfll_writel(td, DFLL_INTR_MAX_MASK | DFLL_INTR_MIN_MASK,
+ DFLL_INTR_STS);
+
+ /* set initial voltage */
+ if ((vinit >= vmin) && vstep) {
+ unsigned int vsel;
+
+ vsel = DIV_ROUND_UP((vinit - vmin), vstep);
+ dfll_force_output(td, vsel);
+ }
+ } else {
+ td->lut_min = 0;
+ td->lut_max = td->lut_size - 1;
+ td->lut_safe = td->lut_min + 1;
+
+ dfll_i2c_writel(td, 0, DFLL_OUTPUT_CFG);
+ val |= (td->lut_safe << DFLL_OUTPUT_CFG_SAFE_SHIFT) |
+ (td->lut_max << DFLL_OUTPUT_CFG_MAX_SHIFT) |
+ (td->lut_min << DFLL_OUTPUT_CFG_MIN_SHIFT);
+ dfll_i2c_writel(td, val, DFLL_OUTPUT_CFG);
+ dfll_i2c_wmb(td);
+
+ dfll_i2c_writel(td, 0, DFLL_OUTPUT_FORCE);
+ dfll_i2c_writel(td, 0, DFLL_INTR_EN);
+ dfll_i2c_writel(td, DFLL_INTR_MAX_MASK | DFLL_INTR_MIN_MASK,
+ DFLL_INTR_STS);
+
+ dfll_load_i2c_lut(td);
+ dfll_init_i2c_if(td);
+ }
}
/*
@@ -643,9 +751,9 @@ static int find_lut_index_for_rate(struct tegra_dfll *td, unsigned long rate)
rcu_read_unlock();
- for (i = 0; i < td->i2c_lut_size; i++) {
- if ((regulator_list_voltage(td->vdd_reg, td->i2c_lut[i]) /
- td->soc->alignment) == align_volt)
+ for (i = 0; i < td->lut_size; i++) {
+ if ((regulator_list_voltage(td->vdd_reg, td->lut[i]) /
+ td->soc->alignment) == align_volt)
return i;
}
@@ -723,7 +831,12 @@ static void dfll_set_frequency_request(struct tegra_dfll *td,
int force_val;
int coef = 128; /* FIXME: td->cg_scale? */;
- force_val = (req->lut_index - td->lut_safe) * coef / td->cg;
+ if (td->pmu_if == TEGRA_DFLL_PMU_PWM)
+ force_val = td->lut[req->lut_index] - td->lut[td->lut_safe];
+ else
+ force_val = req->lut_index - td->lut_safe;
+
+ force_val = force_val * coef / td->cg;
force_val = clamp(force_val, FORCE_MIN, FORCE_MAX);
val |= req->mult_bits << DFLL_FREQ_REQ_MULT_SHIFT;
@@ -867,9 +980,14 @@ static int dfll_lock(struct tegra_dfll *td)
return -EINVAL;
}
- dfll_i2c_set_output_enabled(td, true);
+ if (td->pmu_if == TEGRA_DFLL_PMU_PWM)
+ tegra_dfll_pwm_output_enable();
+ else
+ dfll_i2c_set_output_enabled(td, true);
+
dfll_set_mode(td, DFLL_CLOSED_LOOP);
dfll_set_frequency_request(td, req);
+ dfll_set_force_output_enabled(td, false);
return 0;
default:
@@ -889,11 +1007,17 @@ static int dfll_lock(struct tegra_dfll *td)
*/
static int dfll_unlock(struct tegra_dfll *td)
{
+
switch (td->mode) {
case DFLL_CLOSED_LOOP:
dfll_set_open_loop_config(td);
dfll_set_mode(td, DFLL_OPEN_LOOP);
- dfll_i2c_set_output_enabled(td, false);
+
+ if (td->pmu_if == TEGRA_DFLL_PMU_PWM)
+ tegra_dfll_pwm_output_disable();
+ else
+ dfll_i2c_set_output_enabled(td, false);
+
return 0;
case DFLL_OPEN_LOOP:
@@ -1160,7 +1284,8 @@ static int attr_registers_show(struct seq_file *s, void *data)
seq_puts(s, "CONTROL REGISTERS:\n");
for (offs = 0; offs <= DFLL_MONITOR_DATA; offs += 4) {
- if (offs == DFLL_OUTPUT_CFG)
+ if (td->pmu_if == TEGRA_DFLL_PMU_I2C &&
+ offs == DFLL_OUTPUT_CFG)
val = dfll_i2c_readl(td, offs);
else
val = dfll_readl(td, offs);
@@ -1168,22 +1293,33 @@ static int attr_registers_show(struct seq_file *s, void *data)
}
seq_puts(s, "\nI2C and INTR REGISTERS:\n");
- for (offs = DFLL_I2C_CFG; offs <= DFLL_I2C_STS; offs += 4)
- seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
- dfll_i2c_readl(td, offs));
- for (offs = DFLL_INTR_STS; offs <= DFLL_INTR_EN; offs += 4)
- seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
- dfll_i2c_readl(td, offs));
+ for (offs = DFLL_I2C_CFG; offs <= DFLL_I2C_STS; offs += 4) {
+ if (td->pmu_if == TEGRA_DFLL_PMU_I2C)
+ val = dfll_i2c_readl(td, offs);
+ else
+ val = dfll_readl(td, offs);
- seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n");
- offs = DFLL_I2C_CLK_DIVISOR;
- seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
- __raw_readl(td->i2c_controller_base + offs));
+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs, val);
+ }
+ for (offs = DFLL_INTR_STS; offs <= DFLL_INTR_EN; offs += 4) {
+ if (td->pmu_if == TEGRA_DFLL_PMU_I2C)
+ val = dfll_i2c_readl(td, offs);
+ else
+ val = dfll_readl(td, offs);
+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs, val);
+ }
- seq_puts(s, "\nLUT:\n");
- for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4)
+ if (td->pmu_if == TEGRA_DFLL_PMU_I2C) {
+ seq_puts(s, "\nINTEGRATED I2C CONTROLLER REGISTERS:\n");
+ offs = DFLL_I2C_CLK_DIVISOR;
seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
- __raw_readl(td->lut_base + offs));
+ __raw_readl(td->i2c_controller_base + offs));
+
+ seq_puts(s, "\nLUT:\n");
+ for (offs = 0; offs < 4 * MAX_DFLL_VOLTAGES; offs += 4)
+ seq_printf(s, "[0x%02x] = 0x%08x\n", offs,
+ __raw_readl(td->lut_base + offs));
+ }
return 0;
}
@@ -1385,9 +1521,11 @@ static int find_vdd_map_entry_exact(struct tegra_dfll *td, int uV)
align_volt = uV / td->soc->alignment;
n_voltages = regulator_count_voltages(td->vdd_reg);
+
for (i = 0; i < n_voltages; i++) {
reg_volt = regulator_list_voltage(td->vdd_reg, i) /
td->soc->alignment;
+
if (reg_volt < 0)
break;
@@ -1409,9 +1547,11 @@ static int find_vdd_map_entry_min(struct tegra_dfll *td, int uV)
align_volt = uV / td->soc->alignment;
n_voltages = regulator_count_voltages(td->vdd_reg);
+
for (i = 0; i < n_voltages; i++) {
reg_volt = regulator_list_voltage(td->vdd_reg, i) /
td->soc->alignment;
+
if (reg_volt < 0)
break;
@@ -1424,7 +1564,7 @@ static int find_vdd_map_entry_min(struct tegra_dfll *td, int uV)
}
/**
- * dfll_build_i2c_lut - build the I2C voltage register lookup table
+ * dfll_build_lut - build the I2C and PWM voltage register lookup table
* @td: DFLL instance
*
* The DFLL hardware has 33 bytes of look-up table RAM that must be filled with
@@ -1433,12 +1573,12 @@ static int find_vdd_map_entry_min(struct tegra_dfll *td, int uV)
* the soc-specific platform driver (td->soc->opp_dev) and the PMIC
* register-to-voltage mapping queried from the regulator framework.
*
- * On success, fills in td->i2c_lut and returns 0, or -err on failure.
+ * On success, fills in td->lut and returns 0, or -err on failure.
*/
-static int dfll_build_i2c_lut(struct tegra_dfll *td)
+static int dfll_build_lut(struct tegra_dfll *td)
{
int ret = -EINVAL;
- int j, v, v_max, v_opp;
+ int j, v, v_max, v_opp, v_min_align;
int selector;
unsigned long rate;
struct dev_pm_opp *opp;
@@ -1454,19 +1594,21 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
}
v_max = dev_pm_opp_get_voltage(opp);
+ v_min_align = DIV_ROUND_UP(td->soc->min_millivolts * 1000,
+ td->soc->alignment) * td->soc->alignment;
+
v = td->soc->min_millivolts * 1000;
lut = find_vdd_map_entry_exact(td, v);
if (lut < 0)
goto out;
- td->i2c_lut[0] = lut;
+ td->lut[0] = lut;
for (j = 1, rate = 0; ; rate++) {
opp = dev_pm_opp_find_freq_ceil(td->soc->dev, &rate);
if (IS_ERR(opp))
break;
v_opp = dev_pm_opp_get_voltage(opp);
-
- if (v_opp <= td->soc->min_millivolts * 1000)
+ if (v_opp <= v_min_align)
td->dvco_rate_min = dev_pm_opp_get_freq(opp);
for (;;) {
@@ -1477,21 +1619,21 @@ static int dfll_build_i2c_lut(struct tegra_dfll *td)
selector = find_vdd_map_entry_min(td, v);
if (selector < 0)
goto out;
- if (selector != td->i2c_lut[j - 1])
- td->i2c_lut[j++] = selector;
+ if (selector != td->lut[j - 1])
+ td->lut[j++] = selector;
}
v = (j == MAX_DFLL_VOLTAGES - 1) ? v_max : v_opp;
selector = find_vdd_map_entry_exact(td, v);
if (selector < 0)
goto out;
- if (selector != td->i2c_lut[j - 1])
- td->i2c_lut[j++] = selector;
+ if (selector != td->lut[j - 1])
+ td->lut[j++] = selector;
if (v >= v_max)
break;
}
- td->i2c_lut_size = j;
+ td->lut_size = j;
if (!td->dvco_rate_min)
dev_err(td->dev, "no opp above DFLL minimum voltage %d mV\n",
@@ -1563,12 +1705,6 @@ static int dfll_fetch_i2c_params(struct tegra_dfll *td)
}
td->i2c_reg = vsel_reg;
- ret = dfll_build_i2c_lut(td);
- if (ret) {
- dev_err(td->dev, "couldn't build I2C LUT\n");
- return ret;
- }
-
return 0;
}
@@ -1601,6 +1737,61 @@ static int dfll_fetch_common_params(struct tegra_dfll *td)
return ok ? 0 : -EINVAL;
}
+/**
+ * dfll_dt_parse - read necessary parameters from the device tree
+ * @td: DFLL instance
+ *
+ * Read necessary DT parameters based on I2C or PWM operation.
+ * Returns 0 on success or -EINVAL on any failure.
+ */
+static int dfll_dt_parse(struct tegra_dfll *td)
+{
+ int ret;
+ struct device_node *dn = td->dev->of_node;
+
+ ret = dfll_fetch_common_params(td);
+ if (ret) {
+ dev_err(td->dev, "couldn't parse device tree parameters\n");
+ return ret;
+ }
+
+ td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu");
+ if (IS_ERR(td->vdd_reg)) {
+ dev_err(td->dev, "couldn't get vdd_cpu regulator\n");
+ return PTR_ERR(td->vdd_reg);
+ }
+
+ /* I2C or PWM interface */
+ if (of_property_read_bool(dn, "nvidia,pwm-to-pmic")) {
+ td->pmu_if = TEGRA_DFLL_PMU_PWM;
+ dev_info(td->dev, "config PMU interface as PWM\n");
+
+ ret = of_property_read_u32(dn, "nvidia,init-uv",
+ &td->reg_init_uV);
+ if (ret) {
+ dev_err(td->dev, "couldn't get initialized voltage\n");
+ return ret;
+ }
+ } else {
+ td->pmu_if = TEGRA_DFLL_PMU_I2C;
+ dev_info(td->dev, "config PMU interface as I2C\n");
+
+ ret = dfll_fetch_i2c_params(td);
+ if (ret) {
+ dev_err(td->dev, "couldn't get I2C parameters\n");
+ return ret;
+ }
+ }
+
+ ret = dfll_build_lut(td);
+ if (ret) {
+ dev_err(td->dev, "couldn't build LUT\n");
+ return ret;
+ }
+
+ return 0;
+}
+
/*
* API exported to per-SoC platform drivers
*/
@@ -1634,10 +1825,10 @@ int tegra_dfll_register(struct platform_device *pdev,
td->soc = soc;
- td->vdd_reg = devm_regulator_get(td->dev, "vdd-cpu");
- if (IS_ERR(td->vdd_reg)) {
- dev_err(td->dev, "couldn't get vdd_cpu regulator\n");
- return PTR_ERR(td->vdd_reg);
+ ret = dfll_dt_parse(td);
+ if (ret) {
+ dev_err(td->dev, "parse device-tree failed\n");
+ return ret;
}
td->dvco_rst = devm_reset_control_get(td->dev, "dvco");
@@ -1646,16 +1837,6 @@ int tegra_dfll_register(struct platform_device *pdev,
return PTR_ERR(td->dvco_rst);
}
- ret = dfll_fetch_common_params(td);
- if (ret) {
- dev_err(td->dev, "couldn't parse device tree parameters\n");
- return ret;
- }
-
- ret = dfll_fetch_i2c_params(td);
- if (ret)
- return ret;
-
mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!mem) {
dev_err(td->dev, "no control register resource\n");
@@ -1668,43 +1849,47 @@ int tegra_dfll_register(struct platform_device *pdev,
return -ENODEV;
}
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!mem) {
- dev_err(td->dev, "no i2c_base resource\n");
- return -ENODEV;
- }
+ if (td->pmu_if == TEGRA_DFLL_PMU_I2C) {
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ if (!mem) {
+ dev_err(td->dev, "no i2c_base resource\n");
+ return -ENODEV;
+ }
- td->i2c_base = devm_ioremap(td->dev, mem->start, resource_size(mem));
- if (!td->i2c_base) {
- dev_err(td->dev, "couldn't ioremap i2c_base resource\n");
- return -ENODEV;
- }
+ td->i2c_base = devm_ioremap(td->dev, mem->start,
+ resource_size(mem));
+ if (!td->i2c_base) {
+ dev_err(td->dev, "couldn't ioremap i2c_base resource\n");
+ return -ENODEV;
+ }
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 2);
- if (!mem) {
- dev_err(td->dev, "no i2c_controller_base resource\n");
- return -ENODEV;
- }
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 2);
+ if (!mem) {
+ dev_err(td->dev, "no i2c_controller_base resource\n");
+ return -ENODEV;
+ }
- td->i2c_controller_base = devm_ioremap(td->dev, mem->start,
+ td->i2c_controller_base = devm_ioremap(td->dev, mem->start,
resource_size(mem));
- if (!td->i2c_controller_base) {
- dev_err(td->dev,
- "couldn't ioremap i2c_controller_base resource\n");
- return -ENODEV;
- }
+ if (!td->i2c_controller_base) {
+ dev_err(td->dev,
+ "couldn't ioremap i2c_controller_base resource\n");
+ return -ENODEV;
+ }
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 3);
- if (!mem) {
- dev_err(td->dev, "no lut_base resource\n");
- return -ENODEV;
- }
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 3);
+ if (!mem) {
+ dev_err(td->dev, "no lut_base resource\n");
+ return -ENODEV;
+ }
- td->lut_base = devm_ioremap(td->dev, mem->start, resource_size(mem));
- if (!td->lut_base) {
- dev_err(td->dev,
- "couldn't ioremap lut_base resource\n");
- return -ENODEV;
+ td->lut_base = devm_ioremap(td->dev, mem->start,
+ resource_size(mem));
+ if (!td->lut_base) {
+ dev_err(td->dev,
+ "couldn't ioremap lut_base resource\n");
+ return -ENODEV;
+ }
}
ret = dfll_init_clks(td);
The DFLL module can autonomously change the supply voltage by communicating with an off-chip PMIC via either I2C or PWM signals. Original driver only supports I2C interface, this patch adds PWM interface support. Signed-off-by: Penny Chiu <pchiu@nvidia.com> --- .../bindings/clock/nvidia,tegra124-dfll.txt | 8 +- drivers/clk/tegra/clk-dfll.c | 399 +++++++++++++++------ 2 files changed, 299 insertions(+), 108 deletions(-)