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, "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("core"); 250 omap_voltage_register_pmic(voltdm, &omap_cpcap_core); 251 252 voltdm = voltdm_lookup("iva"); 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
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.