aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/regulator/ti-abb-regulator.c
diff options
context:
space:
mode:
authorNishanth Menon <nm@ti.com>2014-01-23 12:57:27 -0500
committerMark Brown <broonie@linaro.org>2014-02-03 07:33:17 -0500
commit6127daa85094e20b42d306dde800e0d745847990 (patch)
treee8f3bf33c4be4889a0798e4dea4af399629d1904 /drivers/regulator/ti-abb-regulator.c
parent38dbfb59d1175ef458d006556061adeaa8751b72 (diff)
regulator: ti-abb: Add support for interleaved LDO registers
Certain platforms such as DRA7 have quirky memory maps such as: PRM_ABBLDO_DSPEVE_CTRL 0x4ae07e20 PRM_ABBLDO_IVA_CTRL 0x4ae07e24 other-registers PRM_ABBLDO_DSPEVE_SETUP 0x4ae07e30 PRM_ABBLDO_IVA_SETUP 0x4ae07e34 These need the address range allocation to be either not reserved OR unique allocation per register instance or use something like syscon based solution. By going with unique allocation per register, we are able to now have a single compatible driver for all instances on all platforms which use the IP block. So, introduce a new "ti,abb-v3" compatible to allow for definitions where explicit register definitions are provided, while maintaining backward compatibility of older predefined register offsets provided by "ti-abb-v1" and "ti-abb-v2". As part of this change, we rename a few variables to indicate the appropriate meaning. Signed-off-by: Nishanth Menon <nm@ti.com> Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/regulator/ti-abb-regulator.c')
-rw-r--r--drivers/regulator/ti-abb-regulator.c86
1 files changed, 57 insertions, 29 deletions
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 */
66struct ti_abb_reg { 66struct 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 */
126static inline u32 ti_abb_rmw(u32 mask, u32 value, u32 offset, 129static 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 */
649static const struct ti_abb_reg abb_regs_v1 = { 648static 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
663static const struct ti_abb_reg abb_regs_v2 = { 662static 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
675static 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
676static const struct of_device_id ti_abb_of_match[] = { 685static 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}