Commit | Line | Data |
---|---|---|
d44fa156 TL |
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> | |
d44fa156 TL |
18 | #include "vc.h" |
19 | ||
20 | /** | |
d33bb8ff | 21 | * omap_cpcap_vsel_to_uv - convert CPCAP VSEL value to microvolts DC |
d44fa156 TL |
22 | * @vsel: CPCAP VSEL value to convert |
23 | * | |
d33bb8ff | 24 | * Returns: the microvolts DC that the CPCAP PMIC should generate when |
d44fa156 TL |
25 | * programmed with @vsel. |
26 | */ | |
821093e1 | 27 | static unsigned long omap_cpcap_vsel_to_uv(unsigned char vsel) |
d44fa156 TL |
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 | * | |
d33bb8ff | 38 | * Returns: the VSEL value necessary for the CPCAP PMIC to |
d44fa156 TL |
39 | * generate an output voltage equal to or greater than @uv microvolts DC. |
40 | */ | |
821093e1 | 41 | static unsigned char omap_cpcap_uv_to_vsel(unsigned long uv) |
d44fa156 TL |
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, | |
c145649b | 62 | .i2c_high_speed = false, |
d44fa156 TL |
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, | |
c0bc969c | 74 | .vddmax = 1375000, |
d44fa156 TL |
75 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, |
76 | .i2c_slave_addr = 0x44, | |
77 | .volt_reg_addr = 0x0, | |
78 | .cmd_reg_addr = 0x01, | |
c145649b | 79 | .i2c_high_speed = false, |
d44fa156 TL |
80 | .vsel_to_uv = omap_cpcap_vsel_to_uv, |
81 | .uv_to_vsel = omap_cpcap_uv_to_vsel, | |
82 | }; | |
83 | ||
84 | /** | |
d33bb8ff | 85 | * omap_max8952_vsel_to_uv - convert MAX8952 VSEL value to microvolts DC |
d44fa156 TL |
86 | * @vsel: MAX8952 VSEL value to convert |
87 | * | |
d33bb8ff | 88 | * Returns: the microvolts DC that the MAX8952 Regulator should generate when |
d44fa156 TL |
89 | * programmed with @vsel. |
90 | */ | |
821093e1 | 91 | static unsigned long omap_max8952_vsel_to_uv(unsigned char vsel) |
d44fa156 TL |
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 | * | |
d33bb8ff | 102 | * Returns: the VSEL value necessary for the MAX8952 Regulator to |
d44fa156 TL |
103 | * generate an output voltage equal to or greater than @uv microvolts DC. |
104 | */ | |
821093e1 | 105 | static unsigned char omap_max8952_uv_to_vsel(unsigned long uv) |
d44fa156 TL |
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, | |
c145649b | 126 | .i2c_high_speed = false, |
d44fa156 TL |
127 | .vsel_to_uv = omap_max8952_vsel_to_uv, |
128 | .uv_to_vsel = omap_max8952_uv_to_vsel, | |
129 | }; | |
130 | ||
131 | /** | |
d33bb8ff | 132 | * omap_fan535503_vsel_to_uv - convert FAN535503 VSEL value to microvolts DC |
d44fa156 TL |
133 | * @vsel: FAN535503 VSEL value to convert |
134 | * | |
d33bb8ff | 135 | * Returns: the microvolts DC that the FAN535503 Regulator should generate when |
d44fa156 TL |
136 | * programmed with @vsel. |
137 | */ | |
821093e1 | 138 | static unsigned long omap_fan535503_vsel_to_uv(unsigned char vsel) |
d44fa156 TL |
139 | { |
140 | /* Extract bits[5:0] */ | |
141 | vsel &= 0x3F; | |
142 | ||
143 | return (((vsel * 125) + 7500)) * 100; | |
144 | } | |
145 | ||
146 | /** | |
d33bb8ff | 147 | * omap_fan535508_vsel_to_uv - convert FAN535508 VSEL value to microvolts DC |
d44fa156 TL |
148 | * @vsel: FAN535508 VSEL value to convert |
149 | * | |
d33bb8ff | 150 | * Returns: the microvolts DC that the FAN535508 Regulator should generate when |
d44fa156 TL |
151 | * programmed with @vsel. |
152 | */ | |
821093e1 | 153 | static unsigned long omap_fan535508_vsel_to_uv(unsigned char vsel) |
d44fa156 TL |
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 | * | |
d33bb8ff | 168 | * Returns: the VSEL value necessary for the MAX8952 Regulator to |
d44fa156 TL |
169 | * generate an output voltage equal to or greater than @uv microvolts DC. |
170 | */ | |
821093e1 | 171 | static unsigned char omap_fan535503_uv_to_vsel(unsigned long uv) |
d44fa156 TL |
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 | * | |
d33bb8ff | 187 | * Returns: the VSEL value necessary for the MAX8952 Regulator to |
d44fa156 TL |
188 | * generate an output voltage equal to or greater than @uv microvolts DC. |
189 | */ | |
821093e1 | 190 | static unsigned char omap_fan535508_uv_to_vsel(unsigned long uv) |
d44fa156 TL |
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, | |
c145649b | 213 | .i2c_high_speed = false, |
d44fa156 TL |
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, | |
c145649b | 233 | .i2c_high_speed = false, |
d44fa156 TL |
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, "motorola,cpcap")) | |
243 | return -ENODEV; | |
244 | ||
245 | voltdm = voltdm_lookup("mpu"); | |
246 | omap_voltage_register_pmic(voltdm, &omap443x_max8952_mpu); | |
247 | ||
248 | if (of_machine_is_compatible("motorola,droid-bionic")) { | |
30916faa | 249 | voltdm = voltdm_lookup("core"); |
d44fa156 TL |
250 | omap_voltage_register_pmic(voltdm, &omap_cpcap_core); |
251 | ||
30916faa | 252 | voltdm = voltdm_lookup("iva"); |
d44fa156 TL |
253 | omap_voltage_register_pmic(voltdm, &omap_cpcap_iva); |
254 | } else { | |
255 | voltdm = voltdm_lookup("core"); | |
256 | omap_voltage_register_pmic(voltdm, &omap4_fan_core); | |
257 | ||
258 | voltdm = voltdm_lookup("iva"); | |
259 | omap_voltage_register_pmic(voltdm, &omap4_fan_iva); | |
260 | } | |
261 | ||
262 | return 0; | |
263 | } | |
c145649b TL |
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); |