18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * pmic-cpcap.c - CPCAP-specific functions for the OPP code 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Adapted from Motorola Mapphone Android Linux kernel 68c2ecf20Sopenharmony_ci * Copyright (C) 2011 Motorola, Inc. 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/err.h> 108c2ecf20Sopenharmony_ci#include <linux/io.h> 118c2ecf20Sopenharmony_ci#include <linux/kernel.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci#include "soc.h" 148c2ecf20Sopenharmony_ci#include "pm.h" 158c2ecf20Sopenharmony_ci#include "voltage.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci#include <linux/init.h> 188c2ecf20Sopenharmony_ci#include "vc.h" 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/** 218c2ecf20Sopenharmony_ci * omap_cpcap_vsel_to_vdc - convert CPCAP VSEL value to microvolts DC 228c2ecf20Sopenharmony_ci * @vsel: CPCAP VSEL value to convert 238c2ecf20Sopenharmony_ci * 248c2ecf20Sopenharmony_ci * Returns the microvolts DC that the CPCAP PMIC should generate when 258c2ecf20Sopenharmony_ci * programmed with @vsel. 268c2ecf20Sopenharmony_ci */ 278c2ecf20Sopenharmony_cistatic unsigned long omap_cpcap_vsel_to_uv(unsigned char vsel) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci if (vsel > 0x44) 308c2ecf20Sopenharmony_ci vsel = 0x44; 318c2ecf20Sopenharmony_ci return (((vsel * 125) + 6000)) * 100; 328c2ecf20Sopenharmony_ci} 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci/** 358c2ecf20Sopenharmony_ci * omap_cpcap_uv_to_vsel - convert microvolts DC to CPCAP VSEL value 368c2ecf20Sopenharmony_ci * @uv: microvolts DC to convert 378c2ecf20Sopenharmony_ci * 388c2ecf20Sopenharmony_ci * Returns the VSEL value necessary for the CPCAP PMIC to 398c2ecf20Sopenharmony_ci * generate an output voltage equal to or greater than @uv microvolts DC. 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_cistatic unsigned char omap_cpcap_uv_to_vsel(unsigned long uv) 428c2ecf20Sopenharmony_ci{ 438c2ecf20Sopenharmony_ci if (uv < 600000) 448c2ecf20Sopenharmony_ci uv = 600000; 458c2ecf20Sopenharmony_ci else if (uv > 1450000) 468c2ecf20Sopenharmony_ci uv = 1450000; 478c2ecf20Sopenharmony_ci return DIV_ROUND_UP(uv - 600000, 12500); 488c2ecf20Sopenharmony_ci} 498c2ecf20Sopenharmony_ci 508c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap_cpcap_core = { 518c2ecf20Sopenharmony_ci .slew_rate = 4000, 528c2ecf20Sopenharmony_ci .step_size = 12500, 538c2ecf20Sopenharmony_ci .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, 548c2ecf20Sopenharmony_ci .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, 558c2ecf20Sopenharmony_ci .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, 568c2ecf20Sopenharmony_ci .vddmin = 900000, 578c2ecf20Sopenharmony_ci .vddmax = 1350000, 588c2ecf20Sopenharmony_ci .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, 598c2ecf20Sopenharmony_ci .i2c_slave_addr = 0x02, 608c2ecf20Sopenharmony_ci .volt_reg_addr = 0x00, 618c2ecf20Sopenharmony_ci .cmd_reg_addr = 0x01, 628c2ecf20Sopenharmony_ci .i2c_high_speed = false, 638c2ecf20Sopenharmony_ci .vsel_to_uv = omap_cpcap_vsel_to_uv, 648c2ecf20Sopenharmony_ci .uv_to_vsel = omap_cpcap_uv_to_vsel, 658c2ecf20Sopenharmony_ci}; 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap_cpcap_iva = { 688c2ecf20Sopenharmony_ci .slew_rate = 4000, 698c2ecf20Sopenharmony_ci .step_size = 12500, 708c2ecf20Sopenharmony_ci .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, 718c2ecf20Sopenharmony_ci .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, 728c2ecf20Sopenharmony_ci .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, 738c2ecf20Sopenharmony_ci .vddmin = 900000, 748c2ecf20Sopenharmony_ci .vddmax = 1375000, 758c2ecf20Sopenharmony_ci .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, 768c2ecf20Sopenharmony_ci .i2c_slave_addr = 0x44, 778c2ecf20Sopenharmony_ci .volt_reg_addr = 0x0, 788c2ecf20Sopenharmony_ci .cmd_reg_addr = 0x01, 798c2ecf20Sopenharmony_ci .i2c_high_speed = false, 808c2ecf20Sopenharmony_ci .vsel_to_uv = omap_cpcap_vsel_to_uv, 818c2ecf20Sopenharmony_ci .uv_to_vsel = omap_cpcap_uv_to_vsel, 828c2ecf20Sopenharmony_ci}; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci/** 858c2ecf20Sopenharmony_ci * omap_max8952_vsel_to_vdc - convert MAX8952 VSEL value to microvolts DC 868c2ecf20Sopenharmony_ci * @vsel: MAX8952 VSEL value to convert 878c2ecf20Sopenharmony_ci * 888c2ecf20Sopenharmony_ci * Returns the microvolts DC that the MAX8952 Regulator should generate when 898c2ecf20Sopenharmony_ci * programmed with @vsel. 908c2ecf20Sopenharmony_ci */ 918c2ecf20Sopenharmony_cistatic unsigned long omap_max8952_vsel_to_uv(unsigned char vsel) 928c2ecf20Sopenharmony_ci{ 938c2ecf20Sopenharmony_ci if (vsel > 0x3F) 948c2ecf20Sopenharmony_ci vsel = 0x3F; 958c2ecf20Sopenharmony_ci return (((vsel * 100) + 7700)) * 100; 968c2ecf20Sopenharmony_ci} 978c2ecf20Sopenharmony_ci 988c2ecf20Sopenharmony_ci/** 998c2ecf20Sopenharmony_ci * omap_max8952_uv_to_vsel - convert microvolts DC to MAX8952 VSEL value 1008c2ecf20Sopenharmony_ci * @uv: microvolts DC to convert 1018c2ecf20Sopenharmony_ci * 1028c2ecf20Sopenharmony_ci * Returns the VSEL value necessary for the MAX8952 Regulator to 1038c2ecf20Sopenharmony_ci * generate an output voltage equal to or greater than @uv microvolts DC. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_cistatic unsigned char omap_max8952_uv_to_vsel(unsigned long uv) 1068c2ecf20Sopenharmony_ci{ 1078c2ecf20Sopenharmony_ci if (uv < 770000) 1088c2ecf20Sopenharmony_ci uv = 770000; 1098c2ecf20Sopenharmony_ci else if (uv > 1400000) 1108c2ecf20Sopenharmony_ci uv = 1400000; 1118c2ecf20Sopenharmony_ci return DIV_ROUND_UP(uv - 770000, 10000); 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap443x_max8952_mpu = { 1158c2ecf20Sopenharmony_ci .slew_rate = 16000, 1168c2ecf20Sopenharmony_ci .step_size = 10000, 1178c2ecf20Sopenharmony_ci .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, 1188c2ecf20Sopenharmony_ci .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, 1198c2ecf20Sopenharmony_ci .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, 1208c2ecf20Sopenharmony_ci .vddmin = 900000, 1218c2ecf20Sopenharmony_ci .vddmax = 1400000, 1228c2ecf20Sopenharmony_ci .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, 1238c2ecf20Sopenharmony_ci .i2c_slave_addr = 0x60, 1248c2ecf20Sopenharmony_ci .volt_reg_addr = 0x03, 1258c2ecf20Sopenharmony_ci .cmd_reg_addr = 0x03, 1268c2ecf20Sopenharmony_ci .i2c_high_speed = false, 1278c2ecf20Sopenharmony_ci .vsel_to_uv = omap_max8952_vsel_to_uv, 1288c2ecf20Sopenharmony_ci .uv_to_vsel = omap_max8952_uv_to_vsel, 1298c2ecf20Sopenharmony_ci}; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci/** 1328c2ecf20Sopenharmony_ci * omap_fan5355_vsel_to_vdc - convert FAN535503 VSEL value to microvolts DC 1338c2ecf20Sopenharmony_ci * @vsel: FAN535503 VSEL value to convert 1348c2ecf20Sopenharmony_ci * 1358c2ecf20Sopenharmony_ci * Returns the microvolts DC that the FAN535503 Regulator should generate when 1368c2ecf20Sopenharmony_ci * programmed with @vsel. 1378c2ecf20Sopenharmony_ci */ 1388c2ecf20Sopenharmony_cistatic unsigned long omap_fan535503_vsel_to_uv(unsigned char vsel) 1398c2ecf20Sopenharmony_ci{ 1408c2ecf20Sopenharmony_ci /* Extract bits[5:0] */ 1418c2ecf20Sopenharmony_ci vsel &= 0x3F; 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci return (((vsel * 125) + 7500)) * 100; 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci/** 1478c2ecf20Sopenharmony_ci * omap_fan535508_vsel_to_vdc - convert FAN535508 VSEL value to microvolts DC 1488c2ecf20Sopenharmony_ci * @vsel: FAN535508 VSEL value to convert 1498c2ecf20Sopenharmony_ci * 1508c2ecf20Sopenharmony_ci * Returns the microvolts DC that the FAN535508 Regulator should generate when 1518c2ecf20Sopenharmony_ci * programmed with @vsel. 1528c2ecf20Sopenharmony_ci */ 1538c2ecf20Sopenharmony_cistatic unsigned long omap_fan535508_vsel_to_uv(unsigned char vsel) 1548c2ecf20Sopenharmony_ci{ 1558c2ecf20Sopenharmony_ci /* Extract bits[5:0] */ 1568c2ecf20Sopenharmony_ci vsel &= 0x3F; 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (vsel > 0x37) 1598c2ecf20Sopenharmony_ci vsel = 0x37; 1608c2ecf20Sopenharmony_ci return (((vsel * 125) + 7500)) * 100; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci/** 1658c2ecf20Sopenharmony_ci * omap_fan535503_uv_to_vsel - convert microvolts DC to FAN535503 VSEL value 1668c2ecf20Sopenharmony_ci * @uv: microvolts DC to convert 1678c2ecf20Sopenharmony_ci * 1688c2ecf20Sopenharmony_ci * Returns the VSEL value necessary for the MAX8952 Regulator to 1698c2ecf20Sopenharmony_ci * generate an output voltage equal to or greater than @uv microvolts DC. 1708c2ecf20Sopenharmony_ci */ 1718c2ecf20Sopenharmony_cistatic unsigned char omap_fan535503_uv_to_vsel(unsigned long uv) 1728c2ecf20Sopenharmony_ci{ 1738c2ecf20Sopenharmony_ci unsigned char vsel; 1748c2ecf20Sopenharmony_ci if (uv < 750000) 1758c2ecf20Sopenharmony_ci uv = 750000; 1768c2ecf20Sopenharmony_ci else if (uv > 1537500) 1778c2ecf20Sopenharmony_ci uv = 1537500; 1788c2ecf20Sopenharmony_ci 1798c2ecf20Sopenharmony_ci vsel = DIV_ROUND_UP(uv - 750000, 12500); 1808c2ecf20Sopenharmony_ci return vsel | 0xC0; 1818c2ecf20Sopenharmony_ci} 1828c2ecf20Sopenharmony_ci 1838c2ecf20Sopenharmony_ci/** 1848c2ecf20Sopenharmony_ci * omap_fan535508_uv_to_vsel - convert microvolts DC to FAN535508 VSEL value 1858c2ecf20Sopenharmony_ci * @uv: microvolts DC to convert 1868c2ecf20Sopenharmony_ci * 1878c2ecf20Sopenharmony_ci * Returns the VSEL value necessary for the MAX8952 Regulator to 1888c2ecf20Sopenharmony_ci * generate an output voltage equal to or greater than @uv microvolts DC. 1898c2ecf20Sopenharmony_ci */ 1908c2ecf20Sopenharmony_cistatic unsigned char omap_fan535508_uv_to_vsel(unsigned long uv) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci unsigned char vsel; 1938c2ecf20Sopenharmony_ci if (uv < 750000) 1948c2ecf20Sopenharmony_ci uv = 750000; 1958c2ecf20Sopenharmony_ci else if (uv > 1437500) 1968c2ecf20Sopenharmony_ci uv = 1437500; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci vsel = DIV_ROUND_UP(uv - 750000, 12500); 1998c2ecf20Sopenharmony_ci return vsel | 0xC0; 2008c2ecf20Sopenharmony_ci} 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_ci/* fan5335-core */ 2038c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap4_fan_core = { 2048c2ecf20Sopenharmony_ci .slew_rate = 4000, 2058c2ecf20Sopenharmony_ci .step_size = 12500, 2068c2ecf20Sopenharmony_ci .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, 2078c2ecf20Sopenharmony_ci .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, 2088c2ecf20Sopenharmony_ci .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, 2098c2ecf20Sopenharmony_ci .vddmin = 850000, 2108c2ecf20Sopenharmony_ci .vddmax = 1375000, 2118c2ecf20Sopenharmony_ci .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, 2128c2ecf20Sopenharmony_ci .i2c_slave_addr = 0x4A, 2138c2ecf20Sopenharmony_ci .i2c_high_speed = false, 2148c2ecf20Sopenharmony_ci .volt_reg_addr = 0x01, 2158c2ecf20Sopenharmony_ci .cmd_reg_addr = 0x01, 2168c2ecf20Sopenharmony_ci .vsel_to_uv = omap_fan535508_vsel_to_uv, 2178c2ecf20Sopenharmony_ci .uv_to_vsel = omap_fan535508_uv_to_vsel, 2188c2ecf20Sopenharmony_ci}; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci/* fan5335 iva */ 2218c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap4_fan_iva = { 2228c2ecf20Sopenharmony_ci .slew_rate = 4000, 2238c2ecf20Sopenharmony_ci .step_size = 12500, 2248c2ecf20Sopenharmony_ci .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, 2258c2ecf20Sopenharmony_ci .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, 2268c2ecf20Sopenharmony_ci .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, 2278c2ecf20Sopenharmony_ci .vddmin = 850000, 2288c2ecf20Sopenharmony_ci .vddmax = 1375000, 2298c2ecf20Sopenharmony_ci .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, 2308c2ecf20Sopenharmony_ci .i2c_slave_addr = 0x48, 2318c2ecf20Sopenharmony_ci .volt_reg_addr = 0x01, 2328c2ecf20Sopenharmony_ci .cmd_reg_addr = 0x01, 2338c2ecf20Sopenharmony_ci .i2c_high_speed = false, 2348c2ecf20Sopenharmony_ci .vsel_to_uv = omap_fan535503_vsel_to_uv, 2358c2ecf20Sopenharmony_ci .uv_to_vsel = omap_fan535503_uv_to_vsel, 2368c2ecf20Sopenharmony_ci}; 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ciint __init omap4_cpcap_init(void) 2398c2ecf20Sopenharmony_ci{ 2408c2ecf20Sopenharmony_ci struct voltagedomain *voltdm; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci if (!of_find_compatible_node(NULL, NULL, "motorola,cpcap")) 2438c2ecf20Sopenharmony_ci return -ENODEV; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci voltdm = voltdm_lookup("mpu"); 2468c2ecf20Sopenharmony_ci omap_voltage_register_pmic(voltdm, &omap443x_max8952_mpu); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (of_machine_is_compatible("motorola,droid-bionic")) { 2498c2ecf20Sopenharmony_ci voltdm = voltdm_lookup("core"); 2508c2ecf20Sopenharmony_ci omap_voltage_register_pmic(voltdm, &omap_cpcap_core); 2518c2ecf20Sopenharmony_ci 2528c2ecf20Sopenharmony_ci voltdm = voltdm_lookup("iva"); 2538c2ecf20Sopenharmony_ci omap_voltage_register_pmic(voltdm, &omap_cpcap_iva); 2548c2ecf20Sopenharmony_ci } else { 2558c2ecf20Sopenharmony_ci voltdm = voltdm_lookup("core"); 2568c2ecf20Sopenharmony_ci omap_voltage_register_pmic(voltdm, &omap4_fan_core); 2578c2ecf20Sopenharmony_ci 2588c2ecf20Sopenharmony_ci voltdm = voltdm_lookup("iva"); 2598c2ecf20Sopenharmony_ci omap_voltage_register_pmic(voltdm, &omap4_fan_iva); 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci return 0; 2638c2ecf20Sopenharmony_ci} 2648c2ecf20Sopenharmony_ci 2658c2ecf20Sopenharmony_cistatic int __init cpcap_late_init(void) 2668c2ecf20Sopenharmony_ci{ 2678c2ecf20Sopenharmony_ci omap4_vc_set_pmic_signaling(PWRDM_POWER_RET); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci return 0; 2708c2ecf20Sopenharmony_ci} 2718c2ecf20Sopenharmony_ciomap_late_initcall(cpcap_late_init); 272