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 */
27static 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 */
41static 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
50static 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
67static 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 */
91static 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 */
105static 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
114static 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 */
138static 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 */
153static 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 */
171static 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 */
190static 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 */
203static 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 */
221static 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
238int __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
265static int __init cpcap_late_init(void)
266{
267 omap4_vc_set_pmic_signaling(PWRDM_POWER_RET);
268
269 return 0;
270}
271omap_late_initcall(cpcap_late_init);
272

source code of linux/arch/arm/mach-omap2/pmic-cpcap.c