blob: 30d1b8945cb7e6430447464848abf74ad216b99b [file] [log] [blame]
Jim Liuab87f942022-11-07 10:48:27 +08001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright (c) 2022 Nuvoton Technology Corp.
4 */
5
Jim Liuab87f942022-11-07 10:48:27 +08006#include <dm.h>
7#include <asm/io.h>
8#include <dm/device_compat.h>
9#include <power/regulator.h>
10
11#define REG_VSRCR 0xf08000e8 /* Voltage Supply Control Register */
12
13/* Supported voltage levels (uV) */
14static const u32 volts_type1[] = { 3300000, 1800000 };
15static const u32 volts_type2[] = { 1000000, 1800000 };
16#define VOLT_LEV0 0
17#define VOLT_LEV1 1
18
19struct volt_supply {
20 char *name;
21 const u32 *volts;
22 u32 reg_shift; /* Register bit offset for setting voltage */
23};
24
25static const struct volt_supply npcm8xx_volt_supps[] = {
26 {"v1", volts_type1, 0},
27 {"v2", volts_type1, 1},
28 {"v3", volts_type1, 2},
29 {"v4", volts_type1, 3},
30 {"v5", volts_type1, 4},
31 {"v6", volts_type1, 5},
32 {"v7", volts_type1, 6},
33 {"v8", volts_type1, 7},
34 {"v9", volts_type1, 8},
35 {"v10", volts_type1, 9},
36 {"v11", volts_type2, 10},
37 {"v12", volts_type1, 11},
38 {"v13", volts_type1, 12},
39 {"v14", volts_type2, 13},
40 {"vsif", volts_type1, 14},
41 {"vr2", volts_type1, 30},
42};
43
44static const struct volt_supply *npcm8xx_volt_supply_get(const char *name)
45{
46 int i;
47
48 for (i = 0; i < ARRAY_SIZE(npcm8xx_volt_supps); i++) {
49 if (!strcmp(npcm8xx_volt_supps[i].name, name))
50 return &npcm8xx_volt_supps[i];
51 }
52
53 return NULL;
54}
55
56static int npcm8xx_regulator_set_value(struct udevice *dev, int uV)
57{
58 struct dm_regulator_uclass_plat *uc_pdata;
59 const struct volt_supply *supp;
60 u32 val, level;
61
62 uc_pdata = dev_get_uclass_plat(dev);
63 if (!uc_pdata)
64 return -ENXIO;
65
66 dev_dbg(dev, "%s set_value: %d\n", uc_pdata->name, uV);
67 supp = npcm8xx_volt_supply_get(uc_pdata->name);
68 if (!supp)
69 return -ENOENT;
70
71 if (uV == supp->volts[VOLT_LEV0])
72 level = VOLT_LEV0;
73 else if (uV == supp->volts[VOLT_LEV1])
74 level = VOLT_LEV1;
75 else
76 return -EINVAL;
77
78 /* Set voltage level */
79 val = readl(REG_VSRCR);
80 val &= ~BIT(supp->reg_shift);
81 val |= level << supp->reg_shift;
82 writel(val, REG_VSRCR);
83
84 return 0;
85}
86
87static int npcm8xx_regulator_get_value(struct udevice *dev)
88{
89 struct dm_regulator_uclass_plat *uc_pdata;
90 const struct volt_supply *supp;
91 u32 val;
92
93 uc_pdata = dev_get_uclass_plat(dev);
94 if (!uc_pdata)
95 return -ENXIO;
96
97 supp = npcm8xx_volt_supply_get(uc_pdata->name);
98 if (!supp)
99 return -ENOENT;
100
101 val = readl(REG_VSRCR) & BIT(supp->reg_shift);
102
103 dev_dbg(dev, "%s get_value: %d\n", uc_pdata->name,
104 val ? supp->volts[VOLT_LEV1] : supp->volts[VOLT_LEV0]);
105
106 return val ? supp->volts[VOLT_LEV1] : supp->volts[VOLT_LEV0];
107}
108
109static int npcm8xx_regulator_set_enable(struct udevice *dev, bool enable)
110{
111 /* Always on */
112 return 0;
113}
114
115static const struct dm_regulator_ops npcm8xx_regulator_ops = {
116 .set_value = npcm8xx_regulator_set_value,
117 .get_value = npcm8xx_regulator_get_value,
118 .set_enable = npcm8xx_regulator_set_enable,
119};
120
121static const struct udevice_id npcm8xx_regulator_ids[] = {
122 { .compatible = "regulator-npcm845" },
123 { },
124};
125
126U_BOOT_DRIVER(regulator_npcm8xx) = {
127 .name = "regulator_npcm845",
128 .id = UCLASS_REGULATOR,
129 .ops = &npcm8xx_regulator_ops,
130 .of_match = npcm8xx_regulator_ids,
131};