diff options
| -rw-r--r-- | Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt | 6 | ||||
| -rw-r--r-- | drivers/regulator/ti-abb-regulator.c | 86 |
2 files changed, 62 insertions, 30 deletions
diff --git a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt index 2e57a33e9029..c58db75f959e 100644 --- a/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt +++ b/Documentation/devicetree/bindings/regulator/ti-abb-regulator.txt | |||
| @@ -4,10 +4,14 @@ Required Properties: | |||
| 4 | - compatible: Should be one of: | 4 | - compatible: Should be one of: |
| 5 | - "ti,abb-v1" for older SoCs like OMAP3 | 5 | - "ti,abb-v1" for older SoCs like OMAP3 |
| 6 | - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5 | 6 | - "ti,abb-v2" for newer SoCs like OMAP4, OMAP5 |
| 7 | - "ti,abb-v3" for a generic definition where setup and control registers are | ||
| 8 | provided (example: DRA7) | ||
| 7 | - reg: Address and length of the register set for the device. It contains | 9 | - reg: Address and length of the register set for the device. It contains |
| 8 | the information of registers in the same order as described by reg-names | 10 | the information of registers in the same order as described by reg-names |
| 9 | - reg-names: Should contain the reg names | 11 | - reg-names: Should contain the reg names |
| 10 | - "base-address" - contains base address of ABB module | 12 | - "base-address" - contains base address of ABB module (ti,abb-v1,ti,abb-v2) |
| 13 | - "control-address" - contains control register address of ABB module (ti,abb-v3) | ||
| 14 | - "setup-address" - contains setup register address of ABB module (ti,abb-v3) | ||
| 11 | - "int-address" - contains address of interrupt register for ABB module | 15 | - "int-address" - contains address of interrupt register for ABB module |
| 12 | (also see Optional properties) | 16 | (also see Optional properties) |
| 13 | - #address-cell: should be 0 | 17 | - #address-cell: should be 0 |
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index b187b6bba7ad..a97d0c5e1097 100644 --- a/drivers/regulator/ti-abb-regulator.c +++ b/drivers/regulator/ti-abb-regulator.c | |||
| @@ -54,8 +54,8 @@ struct ti_abb_info { | |||
| 54 | 54 | ||
| 55 | /** | 55 | /** |
| 56 | * struct ti_abb_reg - Register description for ABB block | 56 | * struct ti_abb_reg - Register description for ABB block |
| 57 | * @setup_reg: setup register offset from base | 57 | * @setup_off: setup register offset from base |
| 58 | * @control_reg: control register offset from base | 58 | * @control_off: control register offset from base |
| 59 | * @sr2_wtcnt_value_mask: setup register- sr2_wtcnt_value mask | 59 | * @sr2_wtcnt_value_mask: setup register- sr2_wtcnt_value mask |
| 60 | * @fbb_sel_mask: setup register- FBB sel mask | 60 | * @fbb_sel_mask: setup register- FBB sel mask |
| 61 | * @rbb_sel_mask: setup register- RBB sel mask | 61 | * @rbb_sel_mask: setup register- RBB sel mask |
| @@ -64,8 +64,8 @@ struct ti_abb_info { | |||
| 64 | * @opp_sel_mask: control register - mask for mode to operate | 64 | * @opp_sel_mask: control register - mask for mode to operate |
| 65 | */ | 65 | */ |
| 66 | struct ti_abb_reg { | 66 | struct ti_abb_reg { |
| 67 | u32 setup_reg; | 67 | u32 setup_off; |
| 68 | u32 control_reg; | 68 | u32 control_off; |
| 69 | 69 | ||
| 70 | /* Setup register fields */ | 70 | /* Setup register fields */ |
| 71 | u32 sr2_wtcnt_value_mask; | 71 | u32 sr2_wtcnt_value_mask; |
| @@ -83,6 +83,8 @@ struct ti_abb_reg { | |||
| 83 | * @rdesc: regulator descriptor | 83 | * @rdesc: regulator descriptor |
| 84 | * @clk: clock(usually sysclk) supplying ABB block | 84 | * @clk: clock(usually sysclk) supplying ABB block |
| 85 | * @base: base address of ABB block | 85 | * @base: base address of ABB block |
| 86 | * @setup_reg: setup register of ABB block | ||
| 87 | * @control_reg: control register of ABB block | ||
| 86 | * @int_base: interrupt register base address | 88 | * @int_base: interrupt register base address |
| 87 | * @efuse_base: (optional) efuse base address for ABB modes | 89 | * @efuse_base: (optional) efuse base address for ABB modes |
| 88 | * @ldo_base: (optional) LDOVBB vset override base address | 90 | * @ldo_base: (optional) LDOVBB vset override base address |
| @@ -99,6 +101,8 @@ struct ti_abb { | |||
| 99 | struct regulator_desc rdesc; | 101 | struct regulator_desc rdesc; |
| 100 | struct clk *clk; | 102 | struct clk *clk; |
| 101 | void __iomem *base; | 103 | void __iomem *base; |
| 104 | void __iomem *setup_reg; | ||
| 105 | void __iomem *control_reg; | ||
| 102 | void __iomem *int_base; | 106 | void __iomem *int_base; |
| 103 | void __iomem *efuse_base; | 107 | void __iomem *efuse_base; |
| 104 | void __iomem *ldo_base; | 108 | void __iomem *ldo_base; |
| @@ -118,20 +122,18 @@ struct ti_abb { | |||
| 118 | * ti_abb_rmw() - handy wrapper to set specific register bits | 122 | * ti_abb_rmw() - handy wrapper to set specific register bits |
| 119 | * @mask: mask for register field | 123 | * @mask: mask for register field |
| 120 | * @value: value shifted to mask location and written | 124 | * @value: value shifted to mask location and written |
| 121 | * @offset: offset of register | 125 | * @reg: register address |
| 122 | * @base: base address | ||
| 123 | * | 126 | * |
| 124 | * Return: final register value (may be unused) | 127 | * Return: final register value (may be unused) |
| 125 | */ | 128 | */ |
| 126 | static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset, | 129 | static inline u32 ti_abb_rmw(u32 mask, u32 value, void __iomem *reg) |
| 127 | void __iomem *base) | ||
| 128 | { | 130 | { |
| 129 | u32 val; | 131 | u32 val; |
| 130 | 132 | ||
| 131 | val = readl(base + offset); | 133 | val = readl(reg); |
| 132 | val &= ~mask; | 134 | val &= ~mask; |
| 133 | val |= (value << __ffs(mask)) & mask; | 135 | val |= (value << __ffs(mask)) & mask; |
| 134 | writel(val, base + offset); | 136 | writel(val, reg); |
| 135 | 137 | ||
| 136 | return val; | 138 | return val; |
| 137 | } | 139 | } |
| @@ -263,21 +265,19 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb, | |||
| 263 | if (ret) | 265 | if (ret) |
| 264 | goto out; | 266 | goto out; |
| 265 | 267 | ||
| 266 | ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, regs->setup_reg, | 268 | ti_abb_rmw(regs->fbb_sel_mask | regs->rbb_sel_mask, 0, abb->setup_reg); |
| 267 | abb->base); | ||
| 268 | 269 | ||
| 269 | switch (info->opp_sel) { | 270 | switch (info->opp_sel) { |
| 270 | case TI_ABB_SLOW_OPP: | 271 | case TI_ABB_SLOW_OPP: |
| 271 | ti_abb_rmw(regs->rbb_sel_mask, 1, regs->setup_reg, abb->base); | 272 | ti_abb_rmw(regs->rbb_sel_mask, 1, abb->setup_reg); |
| 272 | break; | 273 | break; |
| 273 | case TI_ABB_FAST_OPP: | 274 | case TI_ABB_FAST_OPP: |
| 274 | ti_abb_rmw(regs->fbb_sel_mask, 1, regs->setup_reg, abb->base); | 275 | ti_abb_rmw(regs->fbb_sel_mask, 1, abb->setup_reg); |
| 275 | break; | 276 | break; |
| 276 | } | 277 | } |
| 277 | 278 | ||
| 278 | /* program next state of ABB ldo */ | 279 | /* program next state of ABB ldo */ |
| 279 | ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, regs->control_reg, | 280 | ti_abb_rmw(regs->opp_sel_mask, info->opp_sel, abb->control_reg); |
| 280 | abb->base); | ||
| 281 | 281 | ||
| 282 | /* | 282 | /* |
| 283 | * program LDO VBB vset override if needed for !bypass mode | 283 | * program LDO VBB vset override if needed for !bypass mode |
| @@ -288,7 +288,7 @@ static int ti_abb_set_opp(struct regulator_dev *rdev, struct ti_abb *abb, | |||
| 288 | ti_abb_program_ldovbb(dev, abb, info); | 288 | ti_abb_program_ldovbb(dev, abb, info); |
| 289 | 289 | ||
| 290 | /* Initiate ABB ldo change */ | 290 | /* Initiate ABB ldo change */ |
| 291 | ti_abb_rmw(regs->opp_change_mask, 1, regs->control_reg, abb->base); | 291 | ti_abb_rmw(regs->opp_change_mask, 1, abb->control_reg); |
| 292 | 292 | ||
| 293 | /* Wait for ABB LDO to complete transition to new Bias setting */ | 293 | /* Wait for ABB LDO to complete transition to new Bias setting */ |
| 294 | ret = ti_abb_wait_txdone(dev, abb); | 294 | ret = ti_abb_wait_txdone(dev, abb); |
| @@ -490,8 +490,7 @@ static int ti_abb_init_timings(struct device *dev, struct ti_abb *abb) | |||
| 490 | dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__, | 490 | dev_dbg(dev, "%s: Clk_rate=%ld, sr2_cnt=0x%08x\n", __func__, |
| 491 | clk_get_rate(abb->clk), sr2_wt_cnt_val); | 491 | clk_get_rate(abb->clk), sr2_wt_cnt_val); |
| 492 | 492 | ||
| 493 | ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, regs->setup_reg, | 493 | ti_abb_rmw(regs->sr2_wtcnt_value_mask, sr2_wt_cnt_val, abb->setup_reg); |
| 494 | abb->base); | ||
| 495 | 494 | ||
| 496 | return 0; | 495 | return 0; |
| 497 | } | 496 | } |
| @@ -648,8 +647,8 @@ static struct regulator_ops ti_abb_reg_ops = { | |||
| 648 | /* Default ABB block offsets, IF this changes in future, create new one */ | 647 | /* Default ABB block offsets, IF this changes in future, create new one */ |
| 649 | static const struct ti_abb_reg abb_regs_v1 = { | 648 | static const struct ti_abb_reg abb_regs_v1 = { |
| 650 | /* WARNING: registers are wrongly documented in TRM */ | 649 | /* WARNING: registers are wrongly documented in TRM */ |
| 651 | .setup_reg = 0x04, | 650 | .setup_off = 0x04, |
| 652 | .control_reg = 0x00, | 651 | .control_off = 0x00, |
| 653 | 652 | ||
| 654 | .sr2_wtcnt_value_mask = (0xff << 8), | 653 | .sr2_wtcnt_value_mask = (0xff << 8), |
| 655 | .fbb_sel_mask = (0x01 << 2), | 654 | .fbb_sel_mask = (0x01 << 2), |
| @@ -661,8 +660,8 @@ static const struct ti_abb_reg abb_regs_v1 = { | |||
| 661 | }; | 660 | }; |
| 662 | 661 | ||
| 663 | static const struct ti_abb_reg abb_regs_v2 = { | 662 | static const struct ti_abb_reg abb_regs_v2 = { |
| 664 | .setup_reg = 0x00, | 663 | .setup_off = 0x00, |
| 665 | .control_reg = 0x04, | 664 | .control_off = 0x04, |
| 666 | 665 | ||
| 667 | .sr2_wtcnt_value_mask = (0xff << 8), | 666 | .sr2_wtcnt_value_mask = (0xff << 8), |
| 668 | .fbb_sel_mask = (0x01 << 2), | 667 | .fbb_sel_mask = (0x01 << 2), |
| @@ -673,9 +672,20 @@ static const struct ti_abb_reg abb_regs_v2 = { | |||
| 673 | .opp_sel_mask = (0x03 << 0), | 672 | .opp_sel_mask = (0x03 << 0), |
| 674 | }; | 673 | }; |
| 675 | 674 | ||
| 675 | static const struct ti_abb_reg abb_regs_generic = { | ||
| 676 | .sr2_wtcnt_value_mask = (0xff << 8), | ||
| 677 | .fbb_sel_mask = (0x01 << 2), | ||
| 678 | .rbb_sel_mask = (0x01 << 1), | ||
| 679 | .sr2_en_mask = (0x01 << 0), | ||
| 680 | |||
| 681 | .opp_change_mask = (0x01 << 2), | ||
| 682 | .opp_sel_mask = (0x03 << 0), | ||
| 683 | }; | ||
| 684 | |||
| 676 | static const struct of_device_id ti_abb_of_match[] = { | 685 | static const struct of_device_id ti_abb_of_match[] = { |
| 677 | {.compatible = "ti,abb-v1", .data = &abb_regs_v1}, | 686 | {.compatible = "ti,abb-v1", .data = &abb_regs_v1}, |
| 678 | {.compatible = "ti,abb-v2", .data = &abb_regs_v2}, | 687 | {.compatible = "ti,abb-v2", .data = &abb_regs_v2}, |
| 688 | {.compatible = "ti,abb-v3", .data = &abb_regs_generic}, | ||
| 679 | { }, | 689 | { }, |
| 680 | }; | 690 | }; |
| 681 | 691 | ||
| @@ -722,11 +732,29 @@ static int ti_abb_probe(struct platform_device *pdev) | |||
| 722 | abb->regs = match->data; | 732 | abb->regs = match->data; |
| 723 | 733 | ||
| 724 | /* Map ABB resources */ | 734 | /* Map ABB resources */ |
| 725 | pname = "base-address"; | 735 | if (abb->regs->setup_off || abb->regs->control_off) { |
| 726 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | 736 | pname = "base-address"; |
| 727 | abb->base = devm_ioremap_resource(dev, res); | 737 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); |
| 728 | if (IS_ERR(abb->base)) | 738 | abb->base = devm_ioremap_resource(dev, res); |
| 729 | return PTR_ERR(abb->base); | 739 | if (IS_ERR(abb->base)) |
| 740 | return PTR_ERR(abb->base); | ||
| 741 | |||
| 742 | abb->setup_reg = abb->base + abb->regs->setup_off; | ||
| 743 | abb->control_reg = abb->base + abb->regs->control_off; | ||
| 744 | |||
| 745 | } else { | ||
| 746 | pname = "control-address"; | ||
| 747 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | ||
| 748 | abb->control_reg = devm_ioremap_resource(dev, res); | ||
| 749 | if (IS_ERR(abb->control_reg)) | ||
| 750 | return PTR_ERR(abb->control_reg); | ||
| 751 | |||
| 752 | pname = "setup-address"; | ||
| 753 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | ||
| 754 | abb->setup_reg = devm_ioremap_resource(dev, res); | ||
| 755 | if (IS_ERR(abb->setup_reg)) | ||
| 756 | return PTR_ERR(abb->setup_reg); | ||
| 757 | } | ||
| 730 | 758 | ||
| 731 | pname = "int-address"; | 759 | pname = "int-address"; |
| 732 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | 760 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); |
| @@ -860,7 +888,7 @@ skip_opt: | |||
| 860 | platform_set_drvdata(pdev, rdev); | 888 | platform_set_drvdata(pdev, rdev); |
| 861 | 889 | ||
| 862 | /* Enable the ldo if not already done by bootloader */ | 890 | /* Enable the ldo if not already done by bootloader */ |
| 863 | ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->regs->setup_reg, abb->base); | 891 | ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg); |
| 864 | 892 | ||
| 865 | return 0; | 893 | return 0; |
| 866 | } | 894 | } |
