diff options
Diffstat (limited to 'drivers/regulator/ti-abb-regulator.c')
-rw-r--r-- | drivers/regulator/ti-abb-regulator.c | 140 |
1 files changed, 80 insertions, 60 deletions
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c index b187b6bba7ad..a2dabb575b97 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 | } |
@@ -508,32 +507,24 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, | |||
508 | struct regulator_init_data *rinit_data) | 507 | struct regulator_init_data *rinit_data) |
509 | { | 508 | { |
510 | struct ti_abb_info *info; | 509 | struct ti_abb_info *info; |
511 | const struct property *prop; | ||
512 | const __be32 *abb_info; | ||
513 | const u32 num_values = 6; | 510 | const u32 num_values = 6; |
514 | char *pname = "ti,abb_info"; | 511 | char *pname = "ti,abb_info"; |
515 | u32 num_entries, i; | 512 | u32 i; |
516 | unsigned int *volt_table; | 513 | unsigned int *volt_table; |
517 | int min_uV = INT_MAX, max_uV = 0; | 514 | int num_entries, min_uV = INT_MAX, max_uV = 0; |
518 | struct regulation_constraints *c = &rinit_data->constraints; | 515 | struct regulation_constraints *c = &rinit_data->constraints; |
519 | 516 | ||
520 | prop = of_find_property(dev->of_node, pname, NULL); | ||
521 | if (!prop) { | ||
522 | dev_err(dev, "No '%s' property?\n", pname); | ||
523 | return -ENODEV; | ||
524 | } | ||
525 | |||
526 | if (!prop->value) { | ||
527 | dev_err(dev, "Empty '%s' property?\n", pname); | ||
528 | return -ENODATA; | ||
529 | } | ||
530 | |||
531 | /* | 517 | /* |
532 | * Each abb_info is a set of n-tuple, where n is num_values, consisting | 518 | * Each abb_info is a set of n-tuple, where n is num_values, consisting |
533 | * of voltage and a set of detection logic for ABB information for that | 519 | * of voltage and a set of detection logic for ABB information for that |
534 | * voltage to apply. | 520 | * voltage to apply. |
535 | */ | 521 | */ |
536 | num_entries = prop->length / sizeof(u32); | 522 | num_entries = of_property_count_u32_elems(dev->of_node, pname); |
523 | if (num_entries < 0) { | ||
524 | dev_err(dev, "No '%s' property?\n", pname); | ||
525 | return num_entries; | ||
526 | } | ||
527 | |||
537 | if (!num_entries || (num_entries % num_values)) { | 528 | if (!num_entries || (num_entries % num_values)) { |
538 | dev_err(dev, "All '%s' list entries need %d vals\n", pname, | 529 | dev_err(dev, "All '%s' list entries need %d vals\n", pname, |
539 | num_values); | 530 | num_values); |
@@ -542,38 +533,38 @@ static int ti_abb_init_table(struct device *dev, struct ti_abb *abb, | |||
542 | num_entries /= num_values; | 533 | num_entries /= num_values; |
543 | 534 | ||
544 | info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL); | 535 | info = devm_kzalloc(dev, sizeof(*info) * num_entries, GFP_KERNEL); |
545 | if (!info) { | 536 | if (!info) |
546 | dev_err(dev, "Can't allocate info table for '%s' property\n", | ||
547 | pname); | ||
548 | return -ENOMEM; | 537 | return -ENOMEM; |
549 | } | 538 | |
550 | abb->info = info; | 539 | abb->info = info; |
551 | 540 | ||
552 | volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries, | 541 | volt_table = devm_kzalloc(dev, sizeof(unsigned int) * num_entries, |
553 | GFP_KERNEL); | 542 | GFP_KERNEL); |
554 | if (!volt_table) { | 543 | if (!volt_table) |
555 | dev_err(dev, "Can't allocate voltage table for '%s' property\n", | ||
556 | pname); | ||
557 | return -ENOMEM; | 544 | return -ENOMEM; |
558 | } | ||
559 | 545 | ||
560 | abb->rdesc.n_voltages = num_entries; | 546 | abb->rdesc.n_voltages = num_entries; |
561 | abb->rdesc.volt_table = volt_table; | 547 | abb->rdesc.volt_table = volt_table; |
562 | /* We do not know where the OPP voltage is at the moment */ | 548 | /* We do not know where the OPP voltage is at the moment */ |
563 | abb->current_info_idx = -EINVAL; | 549 | abb->current_info_idx = -EINVAL; |
564 | 550 | ||
565 | abb_info = prop->value; | ||
566 | for (i = 0; i < num_entries; i++, info++, volt_table++) { | 551 | for (i = 0; i < num_entries; i++, info++, volt_table++) { |
567 | u32 efuse_offset, rbb_mask, fbb_mask, vset_mask; | 552 | u32 efuse_offset, rbb_mask, fbb_mask, vset_mask; |
568 | u32 efuse_val; | 553 | u32 efuse_val; |
569 | 554 | ||
570 | /* NOTE: num_values should equal to entries picked up here */ | 555 | /* NOTE: num_values should equal to entries picked up here */ |
571 | *volt_table = be32_to_cpup(abb_info++); | 556 | of_property_read_u32_index(dev->of_node, pname, i * num_values, |
572 | info->opp_sel = be32_to_cpup(abb_info++); | 557 | volt_table); |
573 | efuse_offset = be32_to_cpup(abb_info++); | 558 | of_property_read_u32_index(dev->of_node, pname, |
574 | rbb_mask = be32_to_cpup(abb_info++); | 559 | i * num_values + 1, &info->opp_sel); |
575 | fbb_mask = be32_to_cpup(abb_info++); | 560 | of_property_read_u32_index(dev->of_node, pname, |
576 | vset_mask = be32_to_cpup(abb_info++); | 561 | i * num_values + 2, &efuse_offset); |
562 | of_property_read_u32_index(dev->of_node, pname, | ||
563 | i * num_values + 3, &rbb_mask); | ||
564 | of_property_read_u32_index(dev->of_node, pname, | ||
565 | i * num_values + 4, &fbb_mask); | ||
566 | of_property_read_u32_index(dev->of_node, pname, | ||
567 | i * num_values + 5, &vset_mask); | ||
577 | 568 | ||
578 | dev_dbg(dev, | 569 | dev_dbg(dev, |
579 | "[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n", | 570 | "[%d]v=%d ABB=%d ef=0x%x rbb=0x%x fbb=0x%x vset=0x%x\n", |
@@ -648,8 +639,8 @@ static struct regulator_ops ti_abb_reg_ops = { | |||
648 | /* Default ABB block offsets, IF this changes in future, create new one */ | 639 | /* Default ABB block offsets, IF this changes in future, create new one */ |
649 | static const struct ti_abb_reg abb_regs_v1 = { | 640 | static const struct ti_abb_reg abb_regs_v1 = { |
650 | /* WARNING: registers are wrongly documented in TRM */ | 641 | /* WARNING: registers are wrongly documented in TRM */ |
651 | .setup_reg = 0x04, | 642 | .setup_off = 0x04, |
652 | .control_reg = 0x00, | 643 | .control_off = 0x00, |
653 | 644 | ||
654 | .sr2_wtcnt_value_mask = (0xff << 8), | 645 | .sr2_wtcnt_value_mask = (0xff << 8), |
655 | .fbb_sel_mask = (0x01 << 2), | 646 | .fbb_sel_mask = (0x01 << 2), |
@@ -661,8 +652,8 @@ static const struct ti_abb_reg abb_regs_v1 = { | |||
661 | }; | 652 | }; |
662 | 653 | ||
663 | static const struct ti_abb_reg abb_regs_v2 = { | 654 | static const struct ti_abb_reg abb_regs_v2 = { |
664 | .setup_reg = 0x00, | 655 | .setup_off = 0x00, |
665 | .control_reg = 0x04, | 656 | .control_off = 0x04, |
666 | 657 | ||
667 | .sr2_wtcnt_value_mask = (0xff << 8), | 658 | .sr2_wtcnt_value_mask = (0xff << 8), |
668 | .fbb_sel_mask = (0x01 << 2), | 659 | .fbb_sel_mask = (0x01 << 2), |
@@ -673,9 +664,20 @@ static const struct ti_abb_reg abb_regs_v2 = { | |||
673 | .opp_sel_mask = (0x03 << 0), | 664 | .opp_sel_mask = (0x03 << 0), |
674 | }; | 665 | }; |
675 | 666 | ||
667 | static const struct ti_abb_reg abb_regs_generic = { | ||
668 | .sr2_wtcnt_value_mask = (0xff << 8), | ||
669 | .fbb_sel_mask = (0x01 << 2), | ||
670 | .rbb_sel_mask = (0x01 << 1), | ||
671 | .sr2_en_mask = (0x01 << 0), | ||
672 | |||
673 | .opp_change_mask = (0x01 << 2), | ||
674 | .opp_sel_mask = (0x03 << 0), | ||
675 | }; | ||
676 | |||
676 | static const struct of_device_id ti_abb_of_match[] = { | 677 | static const struct of_device_id ti_abb_of_match[] = { |
677 | {.compatible = "ti,abb-v1", .data = &abb_regs_v1}, | 678 | {.compatible = "ti,abb-v1", .data = &abb_regs_v1}, |
678 | {.compatible = "ti,abb-v2", .data = &abb_regs_v2}, | 679 | {.compatible = "ti,abb-v2", .data = &abb_regs_v2}, |
680 | {.compatible = "ti,abb-v3", .data = &abb_regs_generic}, | ||
679 | { }, | 681 | { }, |
680 | }; | 682 | }; |
681 | 683 | ||
@@ -722,11 +724,29 @@ static int ti_abb_probe(struct platform_device *pdev) | |||
722 | abb->regs = match->data; | 724 | abb->regs = match->data; |
723 | 725 | ||
724 | /* Map ABB resources */ | 726 | /* Map ABB resources */ |
725 | pname = "base-address"; | 727 | if (abb->regs->setup_off || abb->regs->control_off) { |
726 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | 728 | pname = "base-address"; |
727 | abb->base = devm_ioremap_resource(dev, res); | 729 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); |
728 | if (IS_ERR(abb->base)) | 730 | abb->base = devm_ioremap_resource(dev, res); |
729 | return PTR_ERR(abb->base); | 731 | if (IS_ERR(abb->base)) |
732 | return PTR_ERR(abb->base); | ||
733 | |||
734 | abb->setup_reg = abb->base + abb->regs->setup_off; | ||
735 | abb->control_reg = abb->base + abb->regs->control_off; | ||
736 | |||
737 | } else { | ||
738 | pname = "control-address"; | ||
739 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | ||
740 | abb->control_reg = devm_ioremap_resource(dev, res); | ||
741 | if (IS_ERR(abb->control_reg)) | ||
742 | return PTR_ERR(abb->control_reg); | ||
743 | |||
744 | pname = "setup-address"; | ||
745 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | ||
746 | abb->setup_reg = devm_ioremap_resource(dev, res); | ||
747 | if (IS_ERR(abb->setup_reg)) | ||
748 | return PTR_ERR(abb->setup_reg); | ||
749 | } | ||
730 | 750 | ||
731 | pname = "int-address"; | 751 | pname = "int-address"; |
732 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); | 752 | res = platform_get_resource_byname(pdev, IORESOURCE_MEM, pname); |
@@ -860,7 +880,7 @@ skip_opt: | |||
860 | platform_set_drvdata(pdev, rdev); | 880 | platform_set_drvdata(pdev, rdev); |
861 | 881 | ||
862 | /* Enable the ldo if not already done by bootloader */ | 882 | /* 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); | 883 | ti_abb_rmw(abb->regs->sr2_en_mask, 1, abb->setup_reg); |
864 | 884 | ||
865 | return 0; | 885 | return 0; |
866 | } | 886 | } |