1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * pmic-cpcap.c - CPCAP-specific functions for the OPP code |
4 | * |
5 | * Adapted from Motorola Mapphone Android Linux kernel |
6 | * Copyright (C) 2011 Motorola, Inc. |
7 | */ |
8 | |
9 | #include <linux/err.h> |
10 | #include <linux/io.h> |
11 | #include <linux/kernel.h> |
12 | |
13 | #include "soc.h" |
14 | #include "pm.h" |
15 | #include "voltage.h" |
16 | |
17 | #include <linux/init.h> |
18 | #include "vc.h" |
19 | |
20 | /** |
21 | * omap_cpcap_vsel_to_uv - convert CPCAP VSEL value to microvolts DC |
22 | * @vsel: CPCAP VSEL value to convert |
23 | * |
24 | * Returns: the microvolts DC that the CPCAP PMIC should generate when |
25 | * programmed with @vsel. |
26 | */ |
27 | static unsigned long omap_cpcap_vsel_to_uv(unsigned char vsel) |
28 | { |
29 | if (vsel > 0x44) |
30 | vsel = 0x44; |
31 | return (((vsel * 125) + 6000)) * 100; |
32 | } |
33 | |
34 | /** |
35 | * omap_cpcap_uv_to_vsel - convert microvolts DC to CPCAP VSEL value |
36 | * @uv: microvolts DC to convert |
37 | * |
38 | * Returns: the VSEL value necessary for the CPCAP PMIC to |
39 | * generate an output voltage equal to or greater than @uv microvolts DC. |
40 | */ |
41 | static unsigned char omap_cpcap_uv_to_vsel(unsigned long uv) |
42 | { |
43 | if (uv < 600000) |
44 | uv = 600000; |
45 | else if (uv > 1450000) |
46 | uv = 1450000; |
47 | return DIV_ROUND_UP(uv - 600000, 12500); |
48 | } |
49 | |
50 | static struct omap_voltdm_pmic omap_cpcap_core = { |
51 | .slew_rate = 4000, |
52 | .step_size = 12500, |
53 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, |
54 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, |
55 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, |
56 | .vddmin = 900000, |
57 | .vddmax = 1350000, |
58 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
59 | .i2c_slave_addr = 0x02, |
60 | .volt_reg_addr = 0x00, |
61 | .cmd_reg_addr = 0x01, |
62 | .i2c_high_speed = false, |
63 | .vsel_to_uv = omap_cpcap_vsel_to_uv, |
64 | .uv_to_vsel = omap_cpcap_uv_to_vsel, |
65 | }; |
66 | |
67 | static struct omap_voltdm_pmic omap_cpcap_iva = { |
68 | .slew_rate = 4000, |
69 | .step_size = 12500, |
70 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, |
71 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, |
72 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, |
73 | .vddmin = 900000, |
74 | .vddmax = 1375000, |
75 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
76 | .i2c_slave_addr = 0x44, |
77 | .volt_reg_addr = 0x0, |
78 | .cmd_reg_addr = 0x01, |
79 | .i2c_high_speed = false, |
80 | .vsel_to_uv = omap_cpcap_vsel_to_uv, |
81 | .uv_to_vsel = omap_cpcap_uv_to_vsel, |
82 | }; |
83 | |
84 | /** |
85 | * omap_max8952_vsel_to_uv - convert MAX8952 VSEL value to microvolts DC |
86 | * @vsel: MAX8952 VSEL value to convert |
87 | * |
88 | * Returns: the microvolts DC that the MAX8952 Regulator should generate when |
89 | * programmed with @vsel. |
90 | */ |
91 | static unsigned long omap_max8952_vsel_to_uv(unsigned char vsel) |
92 | { |
93 | if (vsel > 0x3F) |
94 | vsel = 0x3F; |
95 | return (((vsel * 100) + 7700)) * 100; |
96 | } |
97 | |
98 | /** |
99 | * omap_max8952_uv_to_vsel - convert microvolts DC to MAX8952 VSEL value |
100 | * @uv: microvolts DC to convert |
101 | * |
102 | * Returns: the VSEL value necessary for the MAX8952 Regulator to |
103 | * generate an output voltage equal to or greater than @uv microvolts DC. |
104 | */ |
105 | static unsigned char omap_max8952_uv_to_vsel(unsigned long uv) |
106 | { |
107 | if (uv < 770000) |
108 | uv = 770000; |
109 | else if (uv > 1400000) |
110 | uv = 1400000; |
111 | return DIV_ROUND_UP(uv - 770000, 10000); |
112 | } |
113 | |
114 | static struct omap_voltdm_pmic omap443x_max8952_mpu = { |
115 | .slew_rate = 16000, |
116 | .step_size = 10000, |
117 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, |
118 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, |
119 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, |
120 | .vddmin = 900000, |
121 | .vddmax = 1400000, |
122 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
123 | .i2c_slave_addr = 0x60, |
124 | .volt_reg_addr = 0x03, |
125 | .cmd_reg_addr = 0x03, |
126 | .i2c_high_speed = false, |
127 | .vsel_to_uv = omap_max8952_vsel_to_uv, |
128 | .uv_to_vsel = omap_max8952_uv_to_vsel, |
129 | }; |
130 | |
131 | /** |
132 | * omap_fan535503_vsel_to_uv - convert FAN535503 VSEL value to microvolts DC |
133 | * @vsel: FAN535503 VSEL value to convert |
134 | * |
135 | * Returns: the microvolts DC that the FAN535503 Regulator should generate when |
136 | * programmed with @vsel. |
137 | */ |
138 | static unsigned long omap_fan535503_vsel_to_uv(unsigned char vsel) |
139 | { |
140 | /* Extract bits[5:0] */ |
141 | vsel &= 0x3F; |
142 | |
143 | return (((vsel * 125) + 7500)) * 100; |
144 | } |
145 | |
146 | /** |
147 | * omap_fan535508_vsel_to_uv - convert FAN535508 VSEL value to microvolts DC |
148 | * @vsel: FAN535508 VSEL value to convert |
149 | * |
150 | * Returns: the microvolts DC that the FAN535508 Regulator should generate when |
151 | * programmed with @vsel. |
152 | */ |
153 | static unsigned long omap_fan535508_vsel_to_uv(unsigned char vsel) |
154 | { |
155 | /* Extract bits[5:0] */ |
156 | vsel &= 0x3F; |
157 | |
158 | if (vsel > 0x37) |
159 | vsel = 0x37; |
160 | return (((vsel * 125) + 7500)) * 100; |
161 | } |
162 | |
163 | |
164 | /** |
165 | * omap_fan535503_uv_to_vsel - convert microvolts DC to FAN535503 VSEL value |
166 | * @uv: microvolts DC to convert |
167 | * |
168 | * Returns: the VSEL value necessary for the MAX8952 Regulator to |
169 | * generate an output voltage equal to or greater than @uv microvolts DC. |
170 | */ |
171 | static unsigned char omap_fan535503_uv_to_vsel(unsigned long uv) |
172 | { |
173 | unsigned char vsel; |
174 | if (uv < 750000) |
175 | uv = 750000; |
176 | else if (uv > 1537500) |
177 | uv = 1537500; |
178 | |
179 | vsel = DIV_ROUND_UP(uv - 750000, 12500); |
180 | return vsel | 0xC0; |
181 | } |
182 | |
183 | /** |
184 | * omap_fan535508_uv_to_vsel - convert microvolts DC to FAN535508 VSEL value |
185 | * @uv: microvolts DC to convert |
186 | * |
187 | * Returns: the VSEL value necessary for the MAX8952 Regulator to |
188 | * generate an output voltage equal to or greater than @uv microvolts DC. |
189 | */ |
190 | static unsigned char omap_fan535508_uv_to_vsel(unsigned long uv) |
191 | { |
192 | unsigned char vsel; |
193 | if (uv < 750000) |
194 | uv = 750000; |
195 | else if (uv > 1437500) |
196 | uv = 1437500; |
197 | |
198 | vsel = DIV_ROUND_UP(uv - 750000, 12500); |
199 | return vsel | 0xC0; |
200 | } |
201 | |
202 | /* fan5335-core */ |
203 | static struct omap_voltdm_pmic omap4_fan_core = { |
204 | .slew_rate = 4000, |
205 | .step_size = 12500, |
206 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, |
207 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, |
208 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, |
209 | .vddmin = 850000, |
210 | .vddmax = 1375000, |
211 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
212 | .i2c_slave_addr = 0x4A, |
213 | .i2c_high_speed = false, |
214 | .volt_reg_addr = 0x01, |
215 | .cmd_reg_addr = 0x01, |
216 | .vsel_to_uv = omap_fan535508_vsel_to_uv, |
217 | .uv_to_vsel = omap_fan535508_uv_to_vsel, |
218 | }; |
219 | |
220 | /* fan5335 iva */ |
221 | static struct omap_voltdm_pmic omap4_fan_iva = { |
222 | .slew_rate = 4000, |
223 | .step_size = 12500, |
224 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, |
225 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, |
226 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, |
227 | .vddmin = 850000, |
228 | .vddmax = 1375000, |
229 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
230 | .i2c_slave_addr = 0x48, |
231 | .volt_reg_addr = 0x01, |
232 | .cmd_reg_addr = 0x01, |
233 | .i2c_high_speed = false, |
234 | .vsel_to_uv = omap_fan535503_vsel_to_uv, |
235 | .uv_to_vsel = omap_fan535503_uv_to_vsel, |
236 | }; |
237 | |
238 | int __init omap4_cpcap_init(void) |
239 | { |
240 | struct voltagedomain *voltdm; |
241 | |
242 | if (!of_find_compatible_node(NULL, NULL, compat: "motorola,cpcap" )) |
243 | return -ENODEV; |
244 | |
245 | voltdm = voltdm_lookup(name: "mpu" ); |
246 | omap_voltage_register_pmic(voltdm, pmic: &omap443x_max8952_mpu); |
247 | |
248 | if (of_machine_is_compatible(compat: "motorola,droid-bionic" )) { |
249 | voltdm = voltdm_lookup(name: "core" ); |
250 | omap_voltage_register_pmic(voltdm, pmic: &omap_cpcap_core); |
251 | |
252 | voltdm = voltdm_lookup(name: "iva" ); |
253 | omap_voltage_register_pmic(voltdm, pmic: &omap_cpcap_iva); |
254 | } else { |
255 | voltdm = voltdm_lookup(name: "core" ); |
256 | omap_voltage_register_pmic(voltdm, pmic: &omap4_fan_core); |
257 | |
258 | voltdm = voltdm_lookup(name: "iva" ); |
259 | omap_voltage_register_pmic(voltdm, pmic: &omap4_fan_iva); |
260 | } |
261 | |
262 | return 0; |
263 | } |
264 | |
265 | static int __init cpcap_late_init(void) |
266 | { |
267 | omap4_vc_set_pmic_signaling(PWRDM_POWER_RET); |
268 | |
269 | return 0; |
270 | } |
271 | omap_late_initcall(cpcap_late_init); |
272 | |