From f9178dad67952673b653315f92620b7a981466e5 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Mon, 6 Jul 2015 09:58:29 +0100 Subject: [PATCH 01/19] regulator: pwm-regulator: Separate voltage-table initialisation Take this out of the main .probe() routine in order to facilitate the introduction of different ways to obtain 'duty cycle' information. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 77 ++++++++++++++++++------------- 1 file changed, 45 insertions(+), 32 deletions(-) diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index ffa96124a5e7..25560fc519b7 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -78,8 +78,7 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, return drvdata->duty_cycle_table[selector].uV; } - -static struct regulator_ops pwm_regulator_voltage_ops = { +static struct regulator_ops pwm_regulator_voltage_table_ops = { .set_voltage_sel = pwm_regulator_set_voltage_sel, .get_voltage_sel = pwm_regulator_get_voltage_sel, .list_voltage = pwm_regulator_list_voltage, @@ -88,20 +87,55 @@ static struct regulator_ops pwm_regulator_voltage_ops = { static struct regulator_desc pwm_regulator_desc = { .name = "pwm-regulator", - .ops = &pwm_regulator_voltage_ops, .type = REGULATOR_VOLTAGE, .owner = THIS_MODULE, .supply_name = "pwm", }; +static int pwm_regulator_init_table(struct platform_device *pdev, + struct pwm_regulator_data *drvdata) +{ + struct device_node *np = pdev->dev.of_node; + struct pwm_voltages *duty_cycle_table; + int length; + int ret; + + of_find_property(np, "voltage-table", &length); + + if ((length < sizeof(*duty_cycle_table)) || + (length % sizeof(*duty_cycle_table))) { + dev_err(&pdev->dev, + "voltage-table length(%d) is invalid\n", + length); + return -EINVAL; + } + + duty_cycle_table = devm_kzalloc(&pdev->dev, length, GFP_KERNEL); + if (!duty_cycle_table) + return -ENOMEM; + + ret = of_property_read_u32_array(np, "voltage-table", + (u32 *)duty_cycle_table, + length / sizeof(u32)); + if (ret) { + dev_err(&pdev->dev, "Failed to read voltage-table\n"); + return ret; + } + + drvdata->duty_cycle_table = duty_cycle_table; + pwm_regulator_desc.ops = &pwm_regulator_voltage_table_ops; + pwm_regulator_desc.n_voltages = length / sizeof(*duty_cycle_table); + + return 0; +} + static int pwm_regulator_probe(struct platform_device *pdev) { struct pwm_regulator_data *drvdata; - struct property *prop; struct regulator_dev *regulator; struct regulator_config config = { }; struct device_node *np = pdev->dev.of_node; - int length, ret; + int ret; if (!np) { dev_err(&pdev->dev, "Device Tree node missing\n"); @@ -112,36 +146,15 @@ static int pwm_regulator_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - /* determine the number of voltage-table */ - prop = of_find_property(np, "voltage-table", &length); - if (!prop) { - dev_err(&pdev->dev, "No voltage-table\n"); + if (of_find_property(np, "voltage-table", NULL)) { + ret = pwm_regulator_init_table(pdev, drvdata); + if (ret) + return ret; + } else { + dev_err(&pdev->dev, "No \"voltage-table\" supplied\n"); return -EINVAL; } - if ((length < sizeof(*drvdata->duty_cycle_table)) || - (length % sizeof(*drvdata->duty_cycle_table))) { - dev_err(&pdev->dev, "voltage-table length(%d) is invalid\n", - length); - return -EINVAL; - } - - pwm_regulator_desc.n_voltages = length / sizeof(*drvdata->duty_cycle_table); - - drvdata->duty_cycle_table = devm_kzalloc(&pdev->dev, - length, GFP_KERNEL); - if (!drvdata->duty_cycle_table) - return -ENOMEM; - - /* read voltage table from DT property */ - ret = of_property_read_u32_array(np, "voltage-table", - (u32 *)drvdata->duty_cycle_table, - length / sizeof(u32)); - if (ret < 0) { - dev_err(&pdev->dev, "read voltage-table failed\n"); - return ret; - } - config.init_data = of_get_regulator_init_data(&pdev->dev, np, &pwm_regulator_desc); if (!config.init_data) From 02258b8bcbb98b28064cc829f7062455da398633 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Jul 2015 16:06:50 +0100 Subject: [PATCH 02/19] regulator: pwm-regulator: Re-write bindings * Add support for continuous-voltage mode * Put more meat on the bones with regards to voltage-table mode * Sort out formatting for ease of consumption Cc: devicetree@vger.kernel.org Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- .../bindings/regulator/pwm-regulator.txt | 68 +++++++++++++++---- 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt index ce91f61feb12..892b36655b3d 100644 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt @@ -1,27 +1,71 @@ -pwm regulator bindings +Bindings for the Generic PWM Regulator +====================================== + +Currently supports 2 modes of operation: + +voltage-table: When in this mode, a voltage table (See below) of + predefined voltage <=> duty-cycle values must be + provided via DT. Limitations are that the regulator can + only operate at the voltages supplied in the table. + Intermediary duty-cycle values which would normally + allow finer grained voltage selection are ignored and + rendered useless. Although more control is given to + the user if the assumptions made in continuous-voltage + mode do not reign true. + +continuous-voltage: This mode uses the regulator's maximum and minimum + supplied voltages specified in the + regulator-{min,max}-microvolt properties to calculate + appropriate duty-cycle values. This allows for a much + more fine grained solution when compared with + voltage-table mode above. This solution does make an + assumption that a %50 duty-cycle value will cause the + regulator voltage to run at half way between the + supplied max_uV and min_uV values. Required properties: -- compatible: Should be "pwm-regulator" -- pwms: OF device-tree PWM specification (see PWM binding pwm.txt) -- voltage-table: voltage and duty table, include 2 members in each set of - brackets, first one is voltage(unit: uv), the next is duty(unit: percent) +-------------------- +- compatible: Should be "pwm-regulator" -Any property defined as part of the core regulator binding defined in -regulator.txt can also be used. +- pwms: PWM specification (See: ../pwm/pwm.txt) -Example: +One of these must be provided: +- voltage-table: Voltage and Duty-Cycle table consisting of 2 cells + First cell is voltage in microvolts (uV) + Second cell is duty-cycle in percent (%) + +- max-duty-cycle: Maximum Duty-Cycle value -- this will normally be + 255 (0xff) for an 8 bit PWM device + +If both are provided, the current default is voltage-table mode. + +Any property defined as part of the core regulator binding can also be used. +(See: ../regulator/regulator.txt) + +Continuous Voltage Example: pwm_regulator { compatible = "pwm-regulator; pwms = <&pwm1 0 8448 0>; + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + max-duty-cycle = <255>; /* 8bit PWM */ + }; + +Voltage Table Example: + pwm_regulator { + compatible = "pwm-regulator; + pwms = <&pwm1 0 8448 0>; + regulator-min-microvolt = <1016000>; + regulator-max-microvolt = <1114000>; + regulator-name = "vdd_logic"; + + /* Voltage Duty-Cycle */ voltage-table = <1114000 0>, <1095000 10>, <1076000 20>, <1056000 30>, <1036000 40>, <1016000 50>; - - regulator-min-microvolt = <1016000>; - regulator-max-microvolt = <1114000>; - regulator-name = "vdd_logic"; }; From 4773be185a0f7c1c09d8966e100c76f4fa9a3227 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Jul 2015 16:06:51 +0100 Subject: [PATCH 03/19] regulator: pwm-regulator: Add support for continuous-voltage The current version of PWM regulator only supports a static table approach, where pre-calculated values are supplied by the vendor and obtained via DT. The continuous-voltage method takes min_uV and max_uV, and divides the difference between them up into a number of slices. The number of slices depend on how large the duty cycle register is. This information is provided by a DT property. As the name alludes, this provides values for a continuous voltage range between min_uV and max_uV, which has obvious benefits over either limited voltage possibilities, or the requirement to provide a large voltage-table. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 114 +++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 8 deletions(-) diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 25560fc519b7..dac145db305c 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -10,6 +10,7 @@ * published by the Free Software Foundation. */ +#include #include #include #include @@ -21,9 +22,16 @@ #include struct pwm_regulator_data { - struct pwm_voltages *duty_cycle_table; + /* Shared */ struct pwm_device *pwm; + + /* Voltage table */ + struct pwm_voltages *duty_cycle_table; int state; + + /* Continuous voltage */ + u32 max_duty_cycle; + int volt_uV; }; struct pwm_voltages { @@ -31,6 +39,9 @@ struct pwm_voltages { unsigned int dutycycle; }; +/** + * Voltage table call-backs + */ static int pwm_regulator_get_voltage_sel(struct regulator_dev *rdev) { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); @@ -78,6 +89,71 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, return drvdata->duty_cycle_table[selector].uV; } + +/** + * Continuous voltage call-backs + */ +static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, + int volt_mV) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + int min_mV = rdev->constraints->min_uV / 1000; + int max_mV = rdev->constraints->max_uV / 1000; + int max_duty_cycle = drvdata->max_duty_cycle; + int vdiff = min_mV - max_mV; + int pwm_code; + int tmp; + + tmp = ((max_duty_cycle - min_mV) * max_duty_cycle) / vdiff; + pwm_code = ((tmp + max_duty_cycle) * volt_mV) / vdiff; + + if (pwm_code < 0) + pwm_code = 0; + if (pwm_code > max_duty_cycle) + pwm_code = max_duty_cycle; + + return pwm_code * 100 / max_duty_cycle; +} + +static int pwm_regulator_get_voltage(struct regulator_dev *rdev) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + + return drvdata->volt_uV; +} + +static int pwm_regulator_set_voltage(struct regulator_dev *rdev, + int min_uV, int max_uV, + unsigned *selector) +{ + struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); + unsigned int ramp_delay = rdev->constraints->ramp_delay; + int duty_cycle; + int ret; + + duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV / 1000); + + ret = pwm_config(drvdata->pwm, + (drvdata->pwm->period / 100) * duty_cycle, + drvdata->pwm->period); + if (ret) { + dev_err(&rdev->dev, "Failed to configure PWM\n"); + return ret; + } + + ret = pwm_enable(drvdata->pwm); + if (ret) { + dev_err(&rdev->dev, "Failed to enable PWM\n"); + return ret; + } + drvdata->volt_uV = min_uV; + + /* Delay required by PWM regulator to settle to the new voltage */ + usleep_range(ramp_delay, ramp_delay + 1000); + + return 0; +} + static struct regulator_ops pwm_regulator_voltage_table_ops = { .set_voltage_sel = pwm_regulator_set_voltage_sel, .get_voltage_sel = pwm_regulator_get_voltage_sel, @@ -85,6 +161,11 @@ static struct regulator_ops pwm_regulator_voltage_table_ops = { .map_voltage = regulator_map_voltage_iterate, }; +static struct regulator_ops pwm_regulator_voltage_continuous_ops = { + .get_voltage = pwm_regulator_get_voltage, + .set_voltage = pwm_regulator_set_voltage, +}; + static struct regulator_desc pwm_regulator_desc = { .name = "pwm-regulator", .type = REGULATOR_VOLTAGE, @@ -129,6 +210,25 @@ static int pwm_regulator_init_table(struct platform_device *pdev, return 0; } +static int pwm_regulator_init_continuous(struct platform_device *pdev, + struct pwm_regulator_data *drvdata) +{ + struct device_node *np = pdev->dev.of_node; + int ret; + + ret = of_property_read_u32(np, "max-duty-cycle", + &drvdata->max_duty_cycle); + if (ret) { + dev_err(&pdev->dev, "Failed to read \"pwm-max-value\"\n"); + return ret; + } + + pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; + pwm_regulator_desc.continuous_voltage_range = true; + + return 0; +} + static int pwm_regulator_probe(struct platform_device *pdev) { struct pwm_regulator_data *drvdata; @@ -146,14 +246,12 @@ static int pwm_regulator_probe(struct platform_device *pdev) if (!drvdata) return -ENOMEM; - if (of_find_property(np, "voltage-table", NULL)) { + if (of_find_property(np, "voltage-table", NULL)) ret = pwm_regulator_init_table(pdev, drvdata); - if (ret) - return ret; - } else { - dev_err(&pdev->dev, "No \"voltage-table\" supplied\n"); - return -EINVAL; - } + else + ret = pwm_regulator_init_continuous(pdev, drvdata); + if (ret) + return ret; config.init_data = of_get_regulator_init_data(&pdev->dev, np, &pwm_regulator_desc); From cae897dec26a9d81dcb5182b13b08450f38d6bde Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Jul 2015 16:06:52 +0100 Subject: [PATCH 04/19] regulator: pwm-regulator: Simplify voltage to duty-cycle call If we reverse some of the logic and change the formula used, we can simplify the function greatly. It is intentional that this function is supplied and then re-worked within the same patch-set. The submission in the previous patch is the tried and tested (i.e. in real releases) method written by ST. This patch contains a simplification provided later. It looks and performs better, but doesn't have the same time-under-test that the original method does. The idea is that we keep some history in order to provide an easy way back i.e. revert. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 25 ++++++------------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index dac145db305c..d5cb267fa192 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -93,26 +93,13 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, /** * Continuous voltage call-backs */ -static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, - int volt_mV) +static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, int req_uV) { - struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); - int min_mV = rdev->constraints->min_uV / 1000; - int max_mV = rdev->constraints->max_uV / 1000; - int max_duty_cycle = drvdata->max_duty_cycle; - int vdiff = min_mV - max_mV; - int pwm_code; - int tmp; + int min_uV = rdev->constraints->min_uV; + int max_uV = rdev->constraints->max_uV; + int diff = max_uV - min_uV; - tmp = ((max_duty_cycle - min_mV) * max_duty_cycle) / vdiff; - pwm_code = ((tmp + max_duty_cycle) * volt_mV) / vdiff; - - if (pwm_code < 0) - pwm_code = 0; - if (pwm_code > max_duty_cycle) - pwm_code = max_duty_cycle; - - return pwm_code * 100 / max_duty_cycle; + return 100 - ((((req_uV * 100) - (min_uV * 100)) / diff)); } static int pwm_regulator_get_voltage(struct regulator_dev *rdev) @@ -131,7 +118,7 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, int duty_cycle; int ret; - duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV / 1000); + duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV); ret = pwm_config(drvdata->pwm, (drvdata->pwm->period / 100) * duty_cycle, From 5ad2cb14f5b8f3cb3d8688115037751b1ff45455 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Tue, 7 Jul 2015 16:06:53 +0100 Subject: [PATCH 05/19] regulator: pwm-regulator: Don't assign structure attributes right away Perhaps this is just personal preference, but ... This patch introduces a new local variable to receive and test regulator initialisation data. It simplifies and cleans up the code making it that little bit easier to read and maintain. The local value is assigned to the structure attribute when all the others are. This is the way we usually do things. Prevents this kind of nonsense: this->is->just.silly = fetch_silly_value(&pointer); if (!this->is->just.silly) { printk("Silly value failed: %d\n", this->is->just.silly); return this->is->just.silly; } Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index d5cb267fa192..cb482089050b 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -218,6 +218,7 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, static int pwm_regulator_probe(struct platform_device *pdev) { + const struct regulator_init_data *init_data; struct pwm_regulator_data *drvdata; struct regulator_dev *regulator; struct regulator_config config = { }; @@ -240,14 +241,15 @@ static int pwm_regulator_probe(struct platform_device *pdev) if (ret) return ret; - config.init_data = of_get_regulator_init_data(&pdev->dev, np, - &pwm_regulator_desc); - if (!config.init_data) + init_data = of_get_regulator_init_data(&pdev->dev, np, + &pwm_regulator_desc); + if (!init_data) return -ENOMEM; config.of_node = np; config.dev = &pdev->dev; config.driver_data = drvdata; + config.init_data = init_data; drvdata->pwm = devm_pwm_get(&pdev->dev, NULL); if (IS_ERR(drvdata->pwm)) { From a505bfb10a0fc6f4342a2521b899d61ff2461e72 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 9 Jul 2015 16:35:26 +0100 Subject: [PATCH 06/19] regulator: pwm-regulator: Ensure headings aren't confused with properties We're using capitalisation and removing the '-' to mitigate confusion. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- Documentation/devicetree/bindings/regulator/pwm-regulator.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt index 892b36655b3d..23b47720b2e4 100644 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt @@ -3,7 +3,7 @@ Bindings for the Generic PWM Regulator Currently supports 2 modes of operation: -voltage-table: When in this mode, a voltage table (See below) of +Voltage Table: When in this mode, a voltage table (See below) of predefined voltage <=> duty-cycle values must be provided via DT. Limitations are that the regulator can only operate at the voltages supplied in the table. @@ -13,7 +13,7 @@ voltage-table: When in this mode, a voltage table (See below) of the user if the assumptions made in continuous-voltage mode do not reign true. -continuous-voltage: This mode uses the regulator's maximum and minimum +Continuous Voltage: This mode uses the regulator's maximum and minimum supplied voltages specified in the regulator-{min,max}-microvolt properties to calculate appropriate duty-cycle values. This allows for a much From f747a1fe7848453957dbdf362a42d7a6735c6ff0 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 9 Jul 2015 16:35:27 +0100 Subject: [PATCH 07/19] regulator: pwm-regulator: Remove obsoleted property In "[3d7ef30] regulator: pwm-regulator: Simplify voltage to duty-cycle call" we stopped using max_duty_cycle, so we can retire it from device data and DT. There is no need to deprecate this property, as it hasn't hit Mainline yet. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/pwm-regulator.txt | 11 ++++------- drivers/regulator/pwm-regulator.c | 9 --------- 2 files changed, 4 insertions(+), 16 deletions(-) diff --git a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt index 23b47720b2e4..ed936f0f34f2 100644 --- a/Documentation/devicetree/bindings/regulator/pwm-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/pwm-regulator.txt @@ -29,15 +29,14 @@ Required properties: - pwms: PWM specification (See: ../pwm/pwm.txt) -One of these must be provided: +Only required for Voltage Table Mode: - voltage-table: Voltage and Duty-Cycle table consisting of 2 cells First cell is voltage in microvolts (uV) Second cell is duty-cycle in percent (%) -- max-duty-cycle: Maximum Duty-Cycle value -- this will normally be - 255 (0xff) for an 8 bit PWM device - -If both are provided, the current default is voltage-table mode. +NB: To be clear, if voltage-table is provided, then the device will be used +in Voltage Table Mode. If no voltage-table is provided, then the device will +be used in Continuous Voltage Mode. Any property defined as part of the core regulator binding can also be used. (See: ../regulator/regulator.txt) @@ -49,8 +48,6 @@ Continuous Voltage Example: regulator-min-microvolt = <1016000>; regulator-max-microvolt = <1114000>; regulator-name = "vdd_logic"; - - max-duty-cycle = <255>; /* 8bit PWM */ }; Voltage Table Example: diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index cb482089050b..d92e66772ec0 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -30,7 +30,6 @@ struct pwm_regulator_data { int state; /* Continuous voltage */ - u32 max_duty_cycle; int volt_uV; }; @@ -201,14 +200,6 @@ static int pwm_regulator_init_continuous(struct platform_device *pdev, struct pwm_regulator_data *drvdata) { struct device_node *np = pdev->dev.of_node; - int ret; - - ret = of_property_read_u32(np, "max-duty-cycle", - &drvdata->max_duty_cycle); - if (ret) { - dev_err(&pdev->dev, "Failed to read \"pwm-max-value\"\n"); - return ret; - } pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; pwm_regulator_desc.continuous_voltage_range = true; From f3f6439d8635d783f145b321db3049369e745799 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Thu, 9 Jul 2015 16:35:28 +0100 Subject: [PATCH 08/19] regulator: pwm-regulator: Small clean-ups Remove over-bracketing, use framework API to fetch PWM period and be more forthcoming that pwm_voltage_to_duty_cycle() actually returns duty cycle as a percentage, rather than a register value. Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index d92e66772ec0..936e387cc532 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -92,13 +92,13 @@ static int pwm_regulator_list_voltage(struct regulator_dev *rdev, /** * Continuous voltage call-backs */ -static int pwm_voltage_to_duty_cycle(struct regulator_dev *rdev, int req_uV) +static int pwm_voltage_to_duty_cycle_percentage(struct regulator_dev *rdev, int req_uV) { int min_uV = rdev->constraints->min_uV; int max_uV = rdev->constraints->max_uV; int diff = max_uV - min_uV; - return 100 - ((((req_uV * 100) - (min_uV * 100)) / diff)); + return 100 - (((req_uV * 100) - (min_uV * 100)) / diff); } static int pwm_regulator_get_voltage(struct regulator_dev *rdev) @@ -114,14 +114,13 @@ static int pwm_regulator_set_voltage(struct regulator_dev *rdev, { struct pwm_regulator_data *drvdata = rdev_get_drvdata(rdev); unsigned int ramp_delay = rdev->constraints->ramp_delay; + unsigned int period = pwm_get_period(drvdata->pwm); int duty_cycle; int ret; - duty_cycle = pwm_voltage_to_duty_cycle(rdev, min_uV); + duty_cycle = pwm_voltage_to_duty_cycle_percentage(rdev, min_uV); - ret = pwm_config(drvdata->pwm, - (drvdata->pwm->period / 100) * duty_cycle, - drvdata->pwm->period); + ret = pwm_config(drvdata->pwm, (period / 100) * duty_cycle, period); if (ret) { dev_err(&rdev->dev, "Failed to configure PWM\n"); return ret; From f293634b5a9e9acbcc1cac29fac7609bd999f868 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 10 Jul 2015 08:45:34 +0100 Subject: [PATCH 09/19] regulator: pwm-regulator: Fix 'unused-variable' warning drivers/regulator/pwm-regulator.c: In function 'pwm_regulator_init_continuous': drivers/regulator/pwm-regulator.c:202:22: warning: unused variable 'np' [-Wunused-variable] struct device_node *np = pdev->dev.of_node; ^ Reported-by: kbuild test robot Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 936e387cc532..a4c2ce92d41f 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -198,8 +198,6 @@ static int pwm_regulator_init_table(struct platform_device *pdev, static int pwm_regulator_init_continuous(struct platform_device *pdev, struct pwm_regulator_data *drvdata) { - struct device_node *np = pdev->dev.of_node; - pwm_regulator_desc.ops = &pwm_regulator_voltage_continuous_ops; pwm_regulator_desc.continuous_voltage_range = true; From b343e08f3c5623d12829ad4965dd4c4e50f86fa2 Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 10 Jul 2015 08:45:35 +0100 Subject: [PATCH 10/19] regulator: pwm-regulator: Fix 'used uninitialized' warning drivers/regulator/pwm-regulator.c: In function 'pwm_regulator_init_table': drivers/regulator/pwm-regulator.c:172:14: warning: 'length' is used uninitialized in this function [-Wuninitialized] if ((length < sizeof(*duty_cycle_table)) || ^ Reported-by: kbuild test robot Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index a4c2ce92d41f..331b85148680 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -163,7 +163,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; struct pwm_voltages *duty_cycle_table; - int length; + int length = 0; int ret; of_find_property(np, "voltage-table", &length); From 60cb65ebf49e6db114c3efeb3971064a6ddbea0e Mon Sep 17 00:00:00 2001 From: Lee Jones Date: Fri, 10 Jul 2015 08:45:36 +0100 Subject: [PATCH 11/19] regulator: pwm-regulator: Fix ' comparison between signed and unsigned integer' warning MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit drivers/regulator/pwm-regulator.c: In function ‘pwm_regulator_init_table’: drivers/regulator/pwm-regulator.c:171:14: warning: comparison between signed and unsigned integer expressions [-Wsign-compare] Signed-off-by: Lee Jones Signed-off-by: Mark Brown --- drivers/regulator/pwm-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c index 331b85148680..fc3166dfcbfa 100644 --- a/drivers/regulator/pwm-regulator.c +++ b/drivers/regulator/pwm-regulator.c @@ -163,7 +163,7 @@ static int pwm_regulator_init_table(struct platform_device *pdev, { struct device_node *np = pdev->dev.of_node; struct pwm_voltages *duty_cycle_table; - int length = 0; + unsigned int length = 0; int ret; of_find_property(np, "voltage-table", &length); From a807a6cc29115a9a43c168fc0d4540b3d9284815 Mon Sep 17 00:00:00 2001 From: Krzysztof Kozlowski Date: Fri, 10 Jul 2015 14:44:00 +0900 Subject: [PATCH 12/19] regulator: drivers: Drop owner assignment from i2c_driver i2c_driver does not need to set an owner because i2c_register_driver() will set it. Signed-off-by: Krzysztof Kozlowski Signed-off-by: Mark Brown --- drivers/regulator/act8865-regulator.c | 1 - drivers/regulator/da9210-regulator.c | 1 - drivers/regulator/da9211-regulator.c | 1 - drivers/regulator/isl6271a-regulator.c | 1 - drivers/regulator/isl9305.c | 1 - drivers/regulator/lp3971.c | 1 - drivers/regulator/lp3972.c | 1 - drivers/regulator/lp872x.c | 1 - drivers/regulator/ltc3589.c | 1 - drivers/regulator/max1586.c | 1 - drivers/regulator/max8660.c | 1 - drivers/regulator/max8973-regulator.c | 1 - drivers/regulator/pfuze100-regulator.c | 1 - drivers/regulator/tps51632-regulator.c | 1 - drivers/regulator/tps62360-regulator.c | 1 - drivers/regulator/tps65023-regulator.c | 1 - 16 files changed, 16 deletions(-) diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c index 2ff73d72ca34..896db168e4bd 100644 --- a/drivers/regulator/act8865-regulator.c +++ b/drivers/regulator/act8865-regulator.c @@ -530,7 +530,6 @@ MODULE_DEVICE_TABLE(i2c, act8865_ids); static struct i2c_driver act8865_pmic_driver = { .driver = { .name = "act8865", - .owner = THIS_MODULE, }, .probe = act8865_pmic_probe, .id_table = act8865_ids, diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c index f0489cb9018b..143a6621b44f 100644 --- a/drivers/regulator/da9210-regulator.c +++ b/drivers/regulator/da9210-regulator.c @@ -184,7 +184,6 @@ MODULE_DEVICE_TABLE(i2c, da9210_i2c_id); static struct i2c_driver da9210_regulator_driver = { .driver = { .name = "da9210", - .owner = THIS_MODULE, }, .probe = da9210_i2c_probe, .id_table = da9210_i2c_id, diff --git a/drivers/regulator/da9211-regulator.c b/drivers/regulator/da9211-regulator.c index df79e4b1946e..ab8914f280c7 100644 --- a/drivers/regulator/da9211-regulator.c +++ b/drivers/regulator/da9211-regulator.c @@ -494,7 +494,6 @@ MODULE_DEVICE_TABLE(of, da9211_dt_ids); static struct i2c_driver da9211_regulator_driver = { .driver = { .name = "da9211", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(da9211_dt_ids), }, .probe = da9211_i2c_probe, diff --git a/drivers/regulator/isl6271a-regulator.c b/drivers/regulator/isl6271a-regulator.c index 6e5da95fa025..4abd8e9c81e5 100644 --- a/drivers/regulator/isl6271a-regulator.c +++ b/drivers/regulator/isl6271a-regulator.c @@ -156,7 +156,6 @@ MODULE_DEVICE_TABLE(i2c, isl6271a_id); static struct i2c_driver isl6271a_i2c_driver = { .driver = { .name = "isl6271a", - .owner = THIS_MODULE, }, .probe = isl6271a_probe, .id_table = isl6271a_id, diff --git a/drivers/regulator/isl9305.c b/drivers/regulator/isl9305.c index 6e3a15fe00f1..eae9d1ffe641 100644 --- a/drivers/regulator/isl9305.c +++ b/drivers/regulator/isl9305.c @@ -195,7 +195,6 @@ MODULE_DEVICE_TABLE(i2c, isl9305_i2c_id); static struct i2c_driver isl9305_regulator_driver = { .driver = { .name = "isl9305", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(isl9305_dt_ids), }, .probe = isl9305_i2c_probe, diff --git a/drivers/regulator/lp3971.c b/drivers/regulator/lp3971.c index 66fd2330dca0..15c25c622edf 100644 --- a/drivers/regulator/lp3971.c +++ b/drivers/regulator/lp3971.c @@ -452,7 +452,6 @@ MODULE_DEVICE_TABLE(i2c, lp3971_i2c_id); static struct i2c_driver lp3971_i2c_driver = { .driver = { .name = "LP3971", - .owner = THIS_MODULE, }, .probe = lp3971_i2c_probe, .id_table = lp3971_i2c_id, diff --git a/drivers/regulator/lp3972.c b/drivers/regulator/lp3972.c index aea485afcc1a..3a7e96e2c7b3 100644 --- a/drivers/regulator/lp3972.c +++ b/drivers/regulator/lp3972.c @@ -550,7 +550,6 @@ MODULE_DEVICE_TABLE(i2c, lp3972_i2c_id); static struct i2c_driver lp3972_i2c_driver = { .driver = { .name = "lp3972", - .owner = THIS_MODULE, }, .probe = lp3972_i2c_probe, .id_table = lp3972_i2c_id, diff --git a/drivers/regulator/lp872x.c b/drivers/regulator/lp872x.c index 3de328ab41f3..171c7625dd67 100644 --- a/drivers/regulator/lp872x.c +++ b/drivers/regulator/lp872x.c @@ -955,7 +955,6 @@ MODULE_DEVICE_TABLE(i2c, lp872x_ids); static struct i2c_driver lp872x_driver = { .driver = { .name = "lp872x", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(lp872x_dt_ids), }, .probe = lp872x_probe, diff --git a/drivers/regulator/ltc3589.c b/drivers/regulator/ltc3589.c index 0ce8e4e0fa73..6e79d2e8963d 100644 --- a/drivers/regulator/ltc3589.c +++ b/drivers/regulator/ltc3589.c @@ -542,7 +542,6 @@ MODULE_DEVICE_TABLE(i2c, ltc3589_i2c_id); static struct i2c_driver ltc3589_driver = { .driver = { .name = DRIVER_NAME, - .owner = THIS_MODULE, }, .probe = ltc3589_probe, .id_table = ltc3589_i2c_id, diff --git a/drivers/regulator/max1586.c b/drivers/regulator/max1586.c index d2a8c64cae42..2c1228d5796a 100644 --- a/drivers/regulator/max1586.c +++ b/drivers/regulator/max1586.c @@ -304,7 +304,6 @@ static struct i2c_driver max1586_pmic_driver = { .probe = max1586_pmic_probe, .driver = { .name = "max1586", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(max1586_of_match), }, .id_table = max1586_id, diff --git a/drivers/regulator/max8660.c b/drivers/regulator/max8660.c index 4071d74fa828..b87f62dd484e 100644 --- a/drivers/regulator/max8660.c +++ b/drivers/regulator/max8660.c @@ -518,7 +518,6 @@ static struct i2c_driver max8660_driver = { .probe = max8660_probe, .driver = { .name = "max8660", - .owner = THIS_MODULE, }, .id_table = max8660_id, }; diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c index 6f2bdad8b4d8..399a85bc907e 100644 --- a/drivers/regulator/max8973-regulator.c +++ b/drivers/regulator/max8973-regulator.c @@ -652,7 +652,6 @@ static struct i2c_driver max8973_i2c_driver = { .driver = { .name = "max8973", .of_match_table = of_max8973_match_tbl, - .owner = THIS_MODULE, }, .probe = max8973_probe, .id_table = max8973_id, diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 8cc8d1877c44..2f66821d53cb 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -643,7 +643,6 @@ static struct i2c_driver pfuze_driver = { .id_table = pfuze_device_id, .driver = { .name = "pfuze100-regulator", - .owner = THIS_MODULE, .of_match_table = pfuze_dt_ids, }, .probe = pfuze100_regulator_probe, diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c index c213e37eb69e..572816e30095 100644 --- a/drivers/regulator/tps51632-regulator.c +++ b/drivers/regulator/tps51632-regulator.c @@ -362,7 +362,6 @@ MODULE_DEVICE_TABLE(i2c, tps51632_id); static struct i2c_driver tps51632_i2c_driver = { .driver = { .name = "tps51632", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tps51632_of_match), }, .probe = tps51632_probe, diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c index a1fd626c6c96..f6a6d36a6533 100644 --- a/drivers/regulator/tps62360-regulator.c +++ b/drivers/regulator/tps62360-regulator.c @@ -515,7 +515,6 @@ MODULE_DEVICE_TABLE(i2c, tps62360_id); static struct i2c_driver tps62360_i2c_driver = { .driver = { .name = "tps62360", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(tps62360_of_match), }, .probe = tps62360_probe, diff --git a/drivers/regulator/tps65023-regulator.c b/drivers/regulator/tps65023-regulator.c index b941e564b3f3..5cc19b44974a 100644 --- a/drivers/regulator/tps65023-regulator.c +++ b/drivers/regulator/tps65023-regulator.c @@ -410,7 +410,6 @@ MODULE_DEVICE_TABLE(i2c, tps_65023_id); static struct i2c_driver tps_65023_i2c_driver = { .driver = { .name = "tps65023", - .owner = THIS_MODULE, }, .probe = tps_65023_probe, .id_table = tps_65023_id, From 678cdb2fbd7e44b8905a8f4e770c694eb77f0395 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Fri, 24 Jul 2015 13:24:40 +0800 Subject: [PATCH 13/19] regulator: mt6311: Add document for mt6311 regulator This patch adds a list of supported regulator names to the devicetree binding documentation for Mediatek MT6311 PMIC. Signed-off-by: Henry Chen Reviewed-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- .../bindings/regulator/mt6311-regulator.txt | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) create mode 100644 Documentation/devicetree/bindings/regulator/mt6311-regulator.txt diff --git a/Documentation/devicetree/bindings/regulator/mt6311-regulator.txt b/Documentation/devicetree/bindings/regulator/mt6311-regulator.txt new file mode 100644 index 000000000000..02649d8b3f5a --- /dev/null +++ b/Documentation/devicetree/bindings/regulator/mt6311-regulator.txt @@ -0,0 +1,35 @@ +Mediatek MT6311 Regulator Driver + +Required properties: +- compatible: "mediatek,mt6311-regulator" +- reg: I2C slave address, usually 0x6b. +- regulators: List of regulators provided by this controller. It is named + to VDVFS and VBIASN. + The definition for each of these nodes is defined using the standard binding + for regulators at Documentation/devicetree/bindings/regulator/regulator.txt. + +The valid names for regulators are: +BUCK: + VDVFS +LDO: + VBIASN + +Example: + mt6311: pmic@6b { + compatible = "mediatek,mt6311-regulator"; + reg = <0x6b>; + + regulators { + mt6311_vcpu_reg: VDVFS { + regulator-name = "VDVFS"; + regulator-min-microvolt = < 600000>; + regulator-max-microvolt = <1400000>; + regulator-ramp-delay = <10000>; + }; + mt6311_ldo_reg: VBIASN { + regulator-name = "VBIASN"; + regulator-min-microvolt = <200000>; + regulator-max-microvolt = <800000>; + }; + }; + }; From 8766018b6ef73ca124d13b0d0a06dec906726cc8 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Fri, 24 Jul 2015 13:24:41 +0800 Subject: [PATCH 14/19] regulator: mt6311: Add support for mt6311 regulator Add regulator support for mt6311. It has 2 regulaotrs - Buck and LDO, provide the related buck/ldo voltage data to the driver, and creates the regulator_desc table. Supported operations for Buck are enabled/disabled and voltage change, only enabled/disabled for LDO. Signed-off-by: Henry Chen Reviewed-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/Kconfig | 9 ++ drivers/regulator/Makefile | 1 + drivers/regulator/mt6311-regulator.c | 180 +++++++++++++++++++++++++++ drivers/regulator/mt6311-regulator.h | 65 ++++++++++ include/linux/regulator/mt6311.h | 29 +++++ 5 files changed, 284 insertions(+) create mode 100644 drivers/regulator/mt6311-regulator.c create mode 100644 drivers/regulator/mt6311-regulator.h create mode 100644 include/linux/regulator/mt6311.h diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig index bef3bde6971b..aab09ac499a0 100644 --- a/drivers/regulator/Kconfig +++ b/drivers/regulator/Kconfig @@ -451,6 +451,15 @@ config REGULATOR_MC13892 Say y here to support the regulators found on the Freescale MC13892 PMIC. +config REGULATOR_MT6311 + tristate "MediaTek MT6311 PMIC" + depends on I2C + help + Say y here to select this option to enable the power regulator of + MediaTek MT6311 PMIC. + This driver supports the control of different power rails of device + through regulator interface. + config REGULATOR_MT6397 tristate "MediaTek MT6397 PMIC" depends on MFD_MT6397 diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile index 91bf76267404..45e790f92715 100644 --- a/drivers/regulator/Makefile +++ b/drivers/regulator/Makefile @@ -60,6 +60,7 @@ obj-$(CONFIG_REGULATOR_MAX77843) += max77843.o obj-$(CONFIG_REGULATOR_MC13783) += mc13783-regulator.o obj-$(CONFIG_REGULATOR_MC13892) += mc13892-regulator.o obj-$(CONFIG_REGULATOR_MC13XXX_CORE) += mc13xxx-regulator-core.o +obj-$(CONFIG_REGULATOR_MT6311) += mt6311-regulator.o obj-$(CONFIG_REGULATOR_MT6397) += mt6397-regulator.o obj-$(CONFIG_REGULATOR_QCOM_RPM) += qcom_rpm-regulator.o obj-$(CONFIG_REGULATOR_QCOM_SPMI) += qcom_spmi-regulator.o diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c new file mode 100644 index 000000000000..096e6202be1c --- /dev/null +++ b/drivers/regulator/mt6311-regulator.c @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Henry Chen + * + * 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 in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; 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 +#include +#include "mt6311-regulator.h" + +static const struct regmap_config mt6311_regmap_config = { + .reg_bits = 8, + .val_bits = 8, + .max_register = MT6311_FQMTR_CON4, +}; + +/* Default limits measured in millivolts and milliamps */ +#define MT6311_MIN_UV 600000 +#define MT6311_MAX_UV 1400000 +#define MT6311_STEP_UV 6250 + +static const struct regulator_linear_range buck_volt_range[] = { + REGULATOR_LINEAR_RANGE(MT6311_MIN_UV, 0, 0x7f, MT6311_STEP_UV), +}; + +static struct regulator_ops mt6311_buck_ops = { + .list_voltage = regulator_list_voltage_linear_range, + .map_voltage = regulator_map_voltage_linear_range, + .set_voltage_sel = regulator_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .set_voltage_time_sel = regulator_set_voltage_time_sel, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +static struct regulator_ops mt6311_ldo_ops = { + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + +#define MT6311_BUCK(_id) \ +{\ + .name = #_id,\ + .ops = &mt6311_buck_ops,\ + .of_match = of_match_ptr(#_id),\ + .regulators_node = of_match_ptr("regulators"),\ + .type = REGULATOR_VOLTAGE,\ + .id = MT6311_ID_##_id,\ + .n_voltages = (MT6311_MAX_UV - MT6311_MIN_UV) / MT6311_STEP_UV + 1,\ + .min_uV = MT6311_MIN_UV,\ + .uV_step = MT6311_STEP_UV,\ + .owner = THIS_MODULE,\ + .linear_ranges = buck_volt_range, \ + .n_linear_ranges = ARRAY_SIZE(buck_volt_range), \ + .enable_reg = MT6311_VDVFS11_CON9,\ + .enable_mask = MT6311_PMIC_VDVFS11_EN_MASK,\ + .vsel_reg = MT6311_VDVFS11_CON12,\ + .vsel_mask = MT6311_PMIC_VDVFS11_VOSEL_MASK,\ +} + +#define MT6311_LDO(_id) \ +{\ + .name = #_id,\ + .ops = &mt6311_ldo_ops,\ + .of_match = of_match_ptr(#_id),\ + .regulators_node = of_match_ptr("regulators"),\ + .type = REGULATOR_VOLTAGE,\ + .id = MT6311_ID_##_id,\ + .owner = THIS_MODULE,\ + .enable_reg = MT6311_LDO_CON3,\ + .enable_mask = MT6311_PMIC_RG_VBIASN_EN_MASK,\ +} + +static struct regulator_desc mt6311_regulators[] = { + MT6311_BUCK(VDVFS), + MT6311_LDO(VBIASN), +}; + +/* + * I2C driver interface functions + */ +static int mt6311_i2c_probe(struct i2c_client *i2c, + const struct i2c_device_id *id) +{ + struct regulator_config config = { }; + struct regulator_dev *rdev; + struct regmap *regmap; + int error, i, ret; + unsigned int data; + + regmap = devm_regmap_init_i2c(i2c, &mt6311_regmap_config); + if (IS_ERR(regmap)) { + error = PTR_ERR(regmap); + dev_err(&i2c->dev, "Failed to allocate register map: %d\n", + error); + return error; + } + + ret = regmap_read(regmap, MT6311_SWCID, &data); + if (ret < 0) { + dev_err(&i2c->dev, "Failed to read DEVICE_ID reg: %d\n", ret); + return ret; + } + + switch (data) { + case MT6311_E1_CID_CODE: + case MT6311_E2_CID_CODE: + case MT6311_E3_CID_CODE: + break; + default: + dev_err(&i2c->dev, "Unsupported device id = 0x%x.\n", data); + return -ENODEV; + } + + for (i = 0; i < MT6311_MAX_REGULATORS; i++) { + config.dev = &i2c->dev; + config.regmap = regmap; + + rdev = devm_regulator_register(&i2c->dev, + &mt6311_regulators[i], &config); + if (IS_ERR(rdev)) { + dev_err(&i2c->dev, + "Failed to register MT6311 regulator\n"); + return PTR_ERR(rdev); + } + } + + return 0; +} + +static const struct i2c_device_id mt6311_i2c_id[] = { + {"mt6311", 0}, + {}, +}; +MODULE_DEVICE_TABLE(i2c, mt6311_i2c_id); + +#ifdef CONFIG_OF +static const struct of_device_id mt6311_dt_ids[] = { + { .compatible = "mediatek,mt6311-regulator", + .data = &mt6311_i2c_id[0] }, + {}, +}; +MODULE_DEVICE_TABLE(of, mt6311_dt_ids); +#endif + +static struct i2c_driver mt6311_regulator_driver = { + .driver = { + .name = "mt6311", + .owner = THIS_MODULE, + .of_match_table = of_match_ptr(mt6311_dt_ids), + }, + .probe = mt6311_i2c_probe, + .id_table = mt6311_i2c_id, +}; + +module_i2c_driver(mt6311_regulator_driver); + +MODULE_AUTHOR("Henry Chen "); +MODULE_DESCRIPTION("Regulator device driver for Mediatek MT6311"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/regulator/mt6311-regulator.h b/drivers/regulator/mt6311-regulator.h new file mode 100644 index 000000000000..5218db46a798 --- /dev/null +++ b/drivers/regulator/mt6311-regulator.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Henry Chen + * + * 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 in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __MT6311_REGULATOR_H__ +#define __MT6311_REGULATOR_H__ + +#define MT6311_SWCID 0x01 + +#define MT6311_TOP_INT_CON 0x18 +#define MT6311_TOP_INT_MON 0x19 + +#define MT6311_VDVFS11_CON0 0x87 +#define MT6311_VDVFS11_CON7 0x88 +#define MT6311_VDVFS11_CON8 0x89 +#define MT6311_VDVFS11_CON9 0x8A +#define MT6311_VDVFS11_CON10 0x8B +#define MT6311_VDVFS11_CON11 0x8C +#define MT6311_VDVFS11_CON12 0x8D +#define MT6311_VDVFS11_CON13 0x8E +#define MT6311_VDVFS11_CON14 0x8F +#define MT6311_VDVFS11_CON15 0x90 +#define MT6311_VDVFS11_CON16 0x91 +#define MT6311_VDVFS11_CON17 0x92 +#define MT6311_VDVFS11_CON18 0x93 +#define MT6311_VDVFS11_CON19 0x94 + +#define MT6311_LDO_CON0 0xCC +#define MT6311_LDO_OCFB0 0xCD +#define MT6311_LDO_CON2 0xCE +#define MT6311_LDO_CON3 0xCF +#define MT6311_LDO_CON4 0xD0 +#define MT6311_FQMTR_CON0 0xD1 +#define MT6311_FQMTR_CON1 0xD2 +#define MT6311_FQMTR_CON2 0xD3 +#define MT6311_FQMTR_CON3 0xD4 +#define MT6311_FQMTR_CON4 0xD5 + +#define MT6311_PMIC_RG_INT_POL_MASK 0x1 +#define MT6311_PMIC_RG_INT_EN_MASK 0x2 +#define MT6311_PMIC_RG_BUCK_OC_INT_STATUS_MASK 0x10 + +#define MT6311_PMIC_VDVFS11_EN_CTRL_MASK 0x1 +#define MT6311_PMIC_VDVFS11_VOSEL_CTRL_MASK 0x2 +#define MT6311_PMIC_VDVFS11_EN_SEL_MASK 0x3 +#define MT6311_PMIC_VDVFS11_VOSEL_SEL_MASK 0xc +#define MT6311_PMIC_VDVFS11_EN_MASK 0x1 +#define MT6311_PMIC_VDVFS11_VOSEL_MASK 0x7F +#define MT6311_PMIC_VDVFS11_VOSEL_ON_MASK 0x7F +#define MT6311_PMIC_VDVFS11_VOSEL_SLEEP_MASK 0x7F +#define MT6311_PMIC_NI_VDVFS11_VOSEL_MASK 0x7F + +#define MT6311_PMIC_RG_VBIASN_EN_MASK 0x1 + +#endif diff --git a/include/linux/regulator/mt6311.h b/include/linux/regulator/mt6311.h new file mode 100644 index 000000000000..8473259395b6 --- /dev/null +++ b/include/linux/regulator/mt6311.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) 2015 MediaTek Inc. + * Author: Henry Chen + * + * 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 in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ + +#ifndef __LINUX_REGULATOR_MT6311_H +#define __LINUX_REGULATOR_MT6311_H + +#define MT6311_MAX_REGULATORS 2 + +enum { + MT6311_ID_VDVFS = 0, + MT6311_ID_VBIASN, +}; + +#define MT6311_E1_CID_CODE 0x10 +#define MT6311_E2_CID_CODE 0x20 +#define MT6311_E3_CID_CODE 0x30 + +#endif /* __LINUX_REGULATOR_MT6311_H */ From 3a003baeec246f604ed1d2e0087560d7f15edcc6 Mon Sep 17 00:00:00 2001 From: Stephen Boyd Date: Fri, 17 Jul 2015 14:41:54 -0700 Subject: [PATCH 15/19] regulator: Add over current protection (OCP) support Some regulators can automatically shut down when they detect an over current event. Add an op (set_over_current_protection) and a DT property + constraint to support this capability. Signed-off-by: Stephen Boyd Signed-off-by: Mark Brown --- .../devicetree/bindings/regulator/regulator.txt | 1 + drivers/regulator/core.c | 9 +++++++++ drivers/regulator/of_regulator.c | 3 +++ include/linux/regulator/driver.h | 1 + include/linux/regulator/machine.h | 1 + 5 files changed, 15 insertions(+) diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt index db88feb28c03..24bd422cecd5 100644 --- a/Documentation/devicetree/bindings/regulator/regulator.txt +++ b/Documentation/devicetree/bindings/regulator/regulator.txt @@ -42,6 +42,7 @@ Optional properties: - regulator-system-load: Load in uA present on regulator that is not captured by any consumer request. - regulator-pull-down: Enable pull down resistor when the regulator is disabled. +- regulator-over-current-protection: Enable over current protection. Deprecated properties: - regulator-compatible: If a regulator chip contains multiple diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index c9f72019bd68..520413e2bca0 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1081,6 +1081,15 @@ static int set_machine_constraints(struct regulator_dev *rdev, } } + if (rdev->constraints->over_current_protection + && ops->set_over_current_protection) { + ret = ops->set_over_current_protection(rdev); + if (ret < 0) { + rdev_err(rdev, "failed to set over current protection\n"); + goto out; + } + } + print_constraints(rdev); return 0; out: diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c index b1c485b24ab2..250700c853bf 100644 --- a/drivers/regulator/of_regulator.c +++ b/drivers/regulator/of_regulator.c @@ -107,6 +107,9 @@ static void of_get_regulation_constraints(struct device_node *np, if (!of_property_read_u32(np, "regulator-system-load", &pval)) constraints->system_load = pval; + constraints->over_current_protection = of_property_read_bool(np, + "regulator-over-current-protection"); + for (i = 0; i < ARRAY_SIZE(regulator_states); i++) { switch (i) { case PM_SUSPEND_MEM: diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h index 4db9fbe4889d..45932228cbf5 100644 --- a/include/linux/regulator/driver.h +++ b/include/linux/regulator/driver.h @@ -148,6 +148,7 @@ struct regulator_ops { int (*get_current_limit) (struct regulator_dev *); int (*set_input_current_limit) (struct regulator_dev *, int lim_uA); + int (*set_over_current_protection) (struct regulator_dev *); /* enable/disable regulator */ int (*enable) (struct regulator_dev *); diff --git a/include/linux/regulator/machine.h b/include/linux/regulator/machine.h index b11be1260129..a1067d0b3991 100644 --- a/include/linux/regulator/machine.h +++ b/include/linux/regulator/machine.h @@ -147,6 +147,7 @@ struct regulation_constraints { unsigned ramp_disable:1; /* disable ramp delay */ unsigned soft_start:1; /* ramp voltage slowly */ unsigned pull_down:1; /* pull down resistor when regulator off */ + unsigned over_current_protection:1; /* auto disable on over current */ }; /** From 53e381627d34c4c7a3ea00c041c38f447828f755 Mon Sep 17 00:00:00 2001 From: Henry Chen Date: Mon, 3 Aug 2015 22:15:51 +0800 Subject: [PATCH 16/19] regulator: mt6311: Modify the maximum voltage of buck. The maximum voltage of buck should be 1.39375V. 1.39375V = 0.6V + 0.00625V * 127, 127 is the max_sel of linear range. Reported-by: Axel Lin signed-off-by: Henry Chen Signed-off-by: Mark Brown --- drivers/regulator/mt6311-regulator.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c index 096e6202be1c..b140da04a657 100644 --- a/drivers/regulator/mt6311-regulator.c +++ b/drivers/regulator/mt6311-regulator.c @@ -34,7 +34,7 @@ static const struct regmap_config mt6311_regmap_config = { /* Default limits measured in millivolts and milliamps */ #define MT6311_MIN_UV 600000 -#define MT6311_MAX_UV 1400000 +#define MT6311_MAX_UV 1393750 #define MT6311_STEP_UV 6250 static const struct regulator_linear_range buck_volt_range[] = { From 08b472f7b602c60c69f278ba1e15535f5c86ee24 Mon Sep 17 00:00:00 2001 From: Axel Lin Date: Thu, 30 Jul 2015 21:06:43 +0800 Subject: [PATCH 17/19] regulator: mt6311: Trivial clean up Make mt6311_buck_ops, mt6311_ldo_ops and mt6311_regulators const and remove unneeded error variable in mt6311_i2c_probe(). Signed-off-by: Axel Lin Signed-off-by: Mark Brown --- drivers/regulator/mt6311-regulator.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c index b140da04a657..2c2c85bf08c5 100644 --- a/drivers/regulator/mt6311-regulator.c +++ b/drivers/regulator/mt6311-regulator.c @@ -41,7 +41,7 @@ static const struct regulator_linear_range buck_volt_range[] = { REGULATOR_LINEAR_RANGE(MT6311_MIN_UV, 0, 0x7f, MT6311_STEP_UV), }; -static struct regulator_ops mt6311_buck_ops = { +static const struct regulator_ops mt6311_buck_ops = { .list_voltage = regulator_list_voltage_linear_range, .map_voltage = regulator_map_voltage_linear_range, .set_voltage_sel = regulator_set_voltage_sel_regmap, @@ -52,7 +52,7 @@ static struct regulator_ops mt6311_buck_ops = { .is_enabled = regulator_is_enabled_regmap, }; -static struct regulator_ops mt6311_ldo_ops = { +static const struct regulator_ops mt6311_ldo_ops = { .enable = regulator_enable_regmap, .disable = regulator_disable_regmap, .is_enabled = regulator_is_enabled_regmap, @@ -91,7 +91,7 @@ static struct regulator_ops mt6311_ldo_ops = { .enable_mask = MT6311_PMIC_RG_VBIASN_EN_MASK,\ } -static struct regulator_desc mt6311_regulators[] = { +static const struct regulator_desc mt6311_regulators[] = { MT6311_BUCK(VDVFS), MT6311_LDO(VBIASN), }; @@ -105,15 +105,15 @@ static int mt6311_i2c_probe(struct i2c_client *i2c, struct regulator_config config = { }; struct regulator_dev *rdev; struct regmap *regmap; - int error, i, ret; + int i, ret; unsigned int data; regmap = devm_regmap_init_i2c(i2c, &mt6311_regmap_config); if (IS_ERR(regmap)) { - error = PTR_ERR(regmap); + ret = PTR_ERR(regmap); dev_err(&i2c->dev, "Failed to allocate register map: %d\n", - error); - return error; + ret); + return ret; } ret = regmap_read(regmap, MT6311_SWCID, &data); From a02daad70214a820988c045494a15dea047c16d4 Mon Sep 17 00:00:00 2001 From: Javier Martinez Canillas Date: Sat, 29 Aug 2015 02:35:13 +0200 Subject: [PATCH 18/19] regulator: pfuze100: Remove unnecessary MODULE_ALIAS() The driver has a I2C device id table that is used to create the modaliases and also "pfuze100-regulator" is not a supported I2C id, so is never used. Signed-off-by: Javier Martinez Canillas Signed-off-by: Mark Brown --- drivers/regulator/pfuze100-regulator.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/regulator/pfuze100-regulator.c b/drivers/regulator/pfuze100-regulator.c index 8cc8d1877c44..d477fbbc2c7b 100644 --- a/drivers/regulator/pfuze100-regulator.c +++ b/drivers/regulator/pfuze100-regulator.c @@ -653,4 +653,3 @@ module_i2c_driver(pfuze_driver); MODULE_AUTHOR("Robin Gong "); MODULE_DESCRIPTION("Regulator Driver for Freescale PFUZE100/PFUZE200 PMIC"); MODULE_LICENSE("GPL v2"); -MODULE_ALIAS("i2c:pfuze100-regulator"); From 6d73aef11760017c37e448d84595dcb44e1c3827 Mon Sep 17 00:00:00 2001 From: kbuild test robot Date: Sun, 30 Aug 2015 20:20:42 +0800 Subject: [PATCH 19/19] regulator: mt6311: fix platform_no_drv_owner.cocci warnings drivers/regulator/mt6311-regulator.c:169:3-8: No need to set .owner here. The core will do it. Remove .owner field if calls are used which set it automatically Generated by: scripts/coccinelle/api/platform_no_drv_owner.cocci Signed-off-by: Fengguang Wu Signed-off-by: Mark Brown --- drivers/regulator/mt6311-regulator.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/regulator/mt6311-regulator.c b/drivers/regulator/mt6311-regulator.c index 2c2c85bf08c5..02c4e5feca8e 100644 --- a/drivers/regulator/mt6311-regulator.c +++ b/drivers/regulator/mt6311-regulator.c @@ -166,7 +166,6 @@ MODULE_DEVICE_TABLE(of, mt6311_dt_ids); static struct i2c_driver mt6311_regulator_driver = { .driver = { .name = "mt6311", - .owner = THIS_MODULE, .of_match_table = of_match_ptr(mt6311_dt_ids), }, .probe = mt6311_i2c_probe,