xref: /openbmc/linux/arch/arm/mach-omap2/pmic-cpcap.c (revision 7b73a9c8)
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_vdc - 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 = 1350000,
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_vdc - 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_fan5355_vsel_to_vdc - 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_vdc - 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, "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")) {
249 		voltdm = voltdm_lookup("mpu");
250 		omap_voltage_register_pmic(voltdm, &omap_cpcap_core);
251 
252 		voltdm = voltdm_lookup("mpu");
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 }
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