18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * OMAP Voltage Controller (VC) interface 38c2ecf20Sopenharmony_ci * 48c2ecf20Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc. 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * This file is licensed under the terms of the GNU General Public 78c2ecf20Sopenharmony_ci * License version 2. This program is licensed "as is" without any 88c2ecf20Sopenharmony_ci * warranty of any kind, whether express or implied. 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/kernel.h> 118c2ecf20Sopenharmony_ci#include <linux/delay.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/bug.h> 148c2ecf20Sopenharmony_ci#include <linux/io.h> 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include <asm/div64.h> 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#include "iomap.h" 198c2ecf20Sopenharmony_ci#include "soc.h" 208c2ecf20Sopenharmony_ci#include "voltage.h" 218c2ecf20Sopenharmony_ci#include "vc.h" 228c2ecf20Sopenharmony_ci#include "prm-regbits-34xx.h" 238c2ecf20Sopenharmony_ci#include "prm-regbits-44xx.h" 248c2ecf20Sopenharmony_ci#include "prm44xx.h" 258c2ecf20Sopenharmony_ci#include "pm.h" 268c2ecf20Sopenharmony_ci#include "scrm44xx.h" 278c2ecf20Sopenharmony_ci#include "control.h" 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_ci#define OMAP4430_VDD_IVA_I2C_DISABLE BIT(14) 308c2ecf20Sopenharmony_ci#define OMAP4430_VDD_MPU_I2C_DISABLE BIT(13) 318c2ecf20Sopenharmony_ci#define OMAP4430_VDD_CORE_I2C_DISABLE BIT(12) 328c2ecf20Sopenharmony_ci#define OMAP4430_VDD_IVA_PRESENCE BIT(9) 338c2ecf20Sopenharmony_ci#define OMAP4430_VDD_MPU_PRESENCE BIT(8) 348c2ecf20Sopenharmony_ci#define OMAP4430_AUTO_CTRL_VDD_IVA(x) ((x) << 4) 358c2ecf20Sopenharmony_ci#define OMAP4430_AUTO_CTRL_VDD_MPU(x) ((x) << 2) 368c2ecf20Sopenharmony_ci#define OMAP4430_AUTO_CTRL_VDD_CORE(x) ((x) << 0) 378c2ecf20Sopenharmony_ci#define OMAP4430_AUTO_CTRL_VDD_RET 2 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#define OMAP4430_VDD_I2C_DISABLE_MASK \ 408c2ecf20Sopenharmony_ci (OMAP4430_VDD_IVA_I2C_DISABLE | \ 418c2ecf20Sopenharmony_ci OMAP4430_VDD_MPU_I2C_DISABLE | \ 428c2ecf20Sopenharmony_ci OMAP4430_VDD_CORE_I2C_DISABLE) 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_ci#define OMAP4_VDD_DEFAULT_VAL \ 458c2ecf20Sopenharmony_ci (OMAP4430_VDD_I2C_DISABLE_MASK | \ 468c2ecf20Sopenharmony_ci OMAP4430_VDD_IVA_PRESENCE | OMAP4430_VDD_MPU_PRESENCE | \ 478c2ecf20Sopenharmony_ci OMAP4430_AUTO_CTRL_VDD_IVA(OMAP4430_AUTO_CTRL_VDD_RET) | \ 488c2ecf20Sopenharmony_ci OMAP4430_AUTO_CTRL_VDD_MPU(OMAP4430_AUTO_CTRL_VDD_RET) | \ 498c2ecf20Sopenharmony_ci OMAP4430_AUTO_CTRL_VDD_CORE(OMAP4430_AUTO_CTRL_VDD_RET)) 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_ci#define OMAP4_VDD_RET_VAL \ 528c2ecf20Sopenharmony_ci (OMAP4_VDD_DEFAULT_VAL & ~OMAP4430_VDD_I2C_DISABLE_MASK) 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/** 558c2ecf20Sopenharmony_ci * struct omap_vc_channel_cfg - describe the cfg_channel bitfield 568c2ecf20Sopenharmony_ci * @sa: bit for slave address 578c2ecf20Sopenharmony_ci * @rav: bit for voltage configuration register 588c2ecf20Sopenharmony_ci * @rac: bit for command configuration register 598c2ecf20Sopenharmony_ci * @racen: enable bit for RAC 608c2ecf20Sopenharmony_ci * @cmd: bit for command value set selection 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * Channel configuration bits, common for OMAP3+ 638c2ecf20Sopenharmony_ci * OMAP3 register: PRM_VC_CH_CONF 648c2ecf20Sopenharmony_ci * OMAP4 register: PRM_VC_CFG_CHANNEL 658c2ecf20Sopenharmony_ci * OMAP5 register: PRM_VC_SMPS_<voltdm>_CONFIG 668c2ecf20Sopenharmony_ci */ 678c2ecf20Sopenharmony_cistruct omap_vc_channel_cfg { 688c2ecf20Sopenharmony_ci u8 sa; 698c2ecf20Sopenharmony_ci u8 rav; 708c2ecf20Sopenharmony_ci u8 rac; 718c2ecf20Sopenharmony_ci u8 racen; 728c2ecf20Sopenharmony_ci u8 cmd; 738c2ecf20Sopenharmony_ci}; 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_cistatic struct omap_vc_channel_cfg vc_default_channel_cfg = { 768c2ecf20Sopenharmony_ci .sa = BIT(0), 778c2ecf20Sopenharmony_ci .rav = BIT(1), 788c2ecf20Sopenharmony_ci .rac = BIT(2), 798c2ecf20Sopenharmony_ci .racen = BIT(3), 808c2ecf20Sopenharmony_ci .cmd = BIT(4), 818c2ecf20Sopenharmony_ci}; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci/* 848c2ecf20Sopenharmony_ci * On OMAP3+, all VC channels have the above default bitfield 858c2ecf20Sopenharmony_ci * configuration, except the OMAP4 MPU channel. This appears 868c2ecf20Sopenharmony_ci * to be a freak accident as every other VC channel has the 878c2ecf20Sopenharmony_ci * default configuration, thus creating a mutant channel config. 888c2ecf20Sopenharmony_ci */ 898c2ecf20Sopenharmony_cistatic struct omap_vc_channel_cfg vc_mutant_channel_cfg = { 908c2ecf20Sopenharmony_ci .sa = BIT(0), 918c2ecf20Sopenharmony_ci .rav = BIT(2), 928c2ecf20Sopenharmony_ci .rac = BIT(3), 938c2ecf20Sopenharmony_ci .racen = BIT(4), 948c2ecf20Sopenharmony_ci .cmd = BIT(1), 958c2ecf20Sopenharmony_ci}; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic struct omap_vc_channel_cfg *vc_cfg_bits; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci/* Default I2C trace length on pcb, 6.3cm. Used for capacitance calculations. */ 1008c2ecf20Sopenharmony_cistatic u32 sr_i2c_pcb_length = 63; 1018c2ecf20Sopenharmony_ci#define CFG_CHANNEL_MASK 0x1f 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci/** 1048c2ecf20Sopenharmony_ci * omap_vc_config_channel - configure VC channel to PMIC mappings 1058c2ecf20Sopenharmony_ci * @voltdm: pointer to voltagdomain defining the desired VC channel 1068c2ecf20Sopenharmony_ci * 1078c2ecf20Sopenharmony_ci * Configures the VC channel to PMIC mappings for the following 1088c2ecf20Sopenharmony_ci * PMIC settings 1098c2ecf20Sopenharmony_ci * - i2c slave address (SA) 1108c2ecf20Sopenharmony_ci * - voltage configuration address (RAV) 1118c2ecf20Sopenharmony_ci * - command configuration address (RAC) and enable bit (RACEN) 1128c2ecf20Sopenharmony_ci * - command values for ON, ONLP, RET and OFF (CMD) 1138c2ecf20Sopenharmony_ci * 1148c2ecf20Sopenharmony_ci * This function currently only allows flexible configuration of the 1158c2ecf20Sopenharmony_ci * non-default channel. Starting with OMAP4, there are more than 2 1168c2ecf20Sopenharmony_ci * channels, with one defined as the default (on OMAP4, it's MPU.) 1178c2ecf20Sopenharmony_ci * Only the non-default channel can be configured. 1188c2ecf20Sopenharmony_ci */ 1198c2ecf20Sopenharmony_cistatic int omap_vc_config_channel(struct voltagedomain *voltdm) 1208c2ecf20Sopenharmony_ci{ 1218c2ecf20Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 1228c2ecf20Sopenharmony_ci 1238c2ecf20Sopenharmony_ci /* 1248c2ecf20Sopenharmony_ci * For default channel, the only configurable bit is RACEN. 1258c2ecf20Sopenharmony_ci * All others must stay at zero (see function comment above.) 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci if (vc->flags & OMAP_VC_CHANNEL_DEFAULT) 1288c2ecf20Sopenharmony_ci vc->cfg_channel &= vc_cfg_bits->racen; 1298c2ecf20Sopenharmony_ci 1308c2ecf20Sopenharmony_ci voltdm->rmw(CFG_CHANNEL_MASK << vc->cfg_channel_sa_shift, 1318c2ecf20Sopenharmony_ci vc->cfg_channel << vc->cfg_channel_sa_shift, 1328c2ecf20Sopenharmony_ci vc->cfg_channel_reg); 1338c2ecf20Sopenharmony_ci 1348c2ecf20Sopenharmony_ci return 0; 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_ci/* Voltage scale and accessory APIs */ 1388c2ecf20Sopenharmony_ciint omap_vc_pre_scale(struct voltagedomain *voltdm, 1398c2ecf20Sopenharmony_ci unsigned long target_volt, 1408c2ecf20Sopenharmony_ci u8 *target_vsel, u8 *current_vsel) 1418c2ecf20Sopenharmony_ci{ 1428c2ecf20Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 1438c2ecf20Sopenharmony_ci u32 vc_cmdval; 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_ci /* Check if sufficient pmic info is available for this vdd */ 1468c2ecf20Sopenharmony_ci if (!voltdm->pmic) { 1478c2ecf20Sopenharmony_ci pr_err("%s: Insufficient pmic info to scale the vdd_%s\n", 1488c2ecf20Sopenharmony_ci __func__, voltdm->name); 1498c2ecf20Sopenharmony_ci return -EINVAL; 1508c2ecf20Sopenharmony_ci } 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci if (!voltdm->pmic->uv_to_vsel) { 1538c2ecf20Sopenharmony_ci pr_err("%s: PMIC function to convert voltage in uV to vsel not registered. Hence unable to scale voltage for vdd_%s\n", 1548c2ecf20Sopenharmony_ci __func__, voltdm->name); 1558c2ecf20Sopenharmony_ci return -ENODATA; 1568c2ecf20Sopenharmony_ci } 1578c2ecf20Sopenharmony_ci 1588c2ecf20Sopenharmony_ci if (!voltdm->read || !voltdm->write) { 1598c2ecf20Sopenharmony_ci pr_err("%s: No read/write API for accessing vdd_%s regs\n", 1608c2ecf20Sopenharmony_ci __func__, voltdm->name); 1618c2ecf20Sopenharmony_ci return -EINVAL; 1628c2ecf20Sopenharmony_ci } 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci *target_vsel = voltdm->pmic->uv_to_vsel(target_volt); 1658c2ecf20Sopenharmony_ci *current_vsel = voltdm->pmic->uv_to_vsel(voltdm->nominal_volt); 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci /* Setting the ON voltage to the new target voltage */ 1688c2ecf20Sopenharmony_ci vc_cmdval = voltdm->read(vc->cmdval_reg); 1698c2ecf20Sopenharmony_ci vc_cmdval &= ~vc->common->cmd_on_mask; 1708c2ecf20Sopenharmony_ci vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift); 1718c2ecf20Sopenharmony_ci voltdm->write(vc_cmdval, vc->cmdval_reg); 1728c2ecf20Sopenharmony_ci 1738c2ecf20Sopenharmony_ci voltdm->vc_param->on = target_volt; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci omap_vp_update_errorgain(voltdm, target_volt); 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci return 0; 1788c2ecf20Sopenharmony_ci} 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_civoid omap_vc_post_scale(struct voltagedomain *voltdm, 1818c2ecf20Sopenharmony_ci unsigned long target_volt, 1828c2ecf20Sopenharmony_ci u8 target_vsel, u8 current_vsel) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci u32 smps_steps = 0, smps_delay = 0; 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci smps_steps = abs(target_vsel - current_vsel); 1878c2ecf20Sopenharmony_ci /* SMPS slew rate / step size. 2us added as buffer. */ 1888c2ecf20Sopenharmony_ci smps_delay = ((smps_steps * voltdm->pmic->step_size) / 1898c2ecf20Sopenharmony_ci voltdm->pmic->slew_rate) + 2; 1908c2ecf20Sopenharmony_ci udelay(smps_delay); 1918c2ecf20Sopenharmony_ci} 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci/* vc_bypass_scale - VC bypass method of voltage scaling */ 1948c2ecf20Sopenharmony_ciint omap_vc_bypass_scale(struct voltagedomain *voltdm, 1958c2ecf20Sopenharmony_ci unsigned long target_volt) 1968c2ecf20Sopenharmony_ci{ 1978c2ecf20Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 1988c2ecf20Sopenharmony_ci u32 loop_cnt = 0, retries_cnt = 0; 1998c2ecf20Sopenharmony_ci u32 vc_valid, vc_bypass_val_reg, vc_bypass_value; 2008c2ecf20Sopenharmony_ci u8 target_vsel, current_vsel; 2018c2ecf20Sopenharmony_ci int ret; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); 2048c2ecf20Sopenharmony_ci if (ret) 2058c2ecf20Sopenharmony_ci return ret; 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci vc_valid = vc->common->valid; 2088c2ecf20Sopenharmony_ci vc_bypass_val_reg = vc->common->bypass_val_reg; 2098c2ecf20Sopenharmony_ci vc_bypass_value = (target_vsel << vc->common->data_shift) | 2108c2ecf20Sopenharmony_ci (vc->volt_reg_addr << vc->common->regaddr_shift) | 2118c2ecf20Sopenharmony_ci (vc->i2c_slave_addr << vc->common->slaveaddr_shift); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci voltdm->write(vc_bypass_value, vc_bypass_val_reg); 2148c2ecf20Sopenharmony_ci voltdm->write(vc_bypass_value | vc_valid, vc_bypass_val_reg); 2158c2ecf20Sopenharmony_ci 2168c2ecf20Sopenharmony_ci vc_bypass_value = voltdm->read(vc_bypass_val_reg); 2178c2ecf20Sopenharmony_ci /* 2188c2ecf20Sopenharmony_ci * Loop till the bypass command is acknowledged from the SMPS. 2198c2ecf20Sopenharmony_ci * NOTE: This is legacy code. The loop count and retry count needs 2208c2ecf20Sopenharmony_ci * to be revisited. 2218c2ecf20Sopenharmony_ci */ 2228c2ecf20Sopenharmony_ci while (!(vc_bypass_value & vc_valid)) { 2238c2ecf20Sopenharmony_ci loop_cnt++; 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ci if (retries_cnt > 10) { 2268c2ecf20Sopenharmony_ci pr_warn("%s: Retry count exceeded\n", __func__); 2278c2ecf20Sopenharmony_ci return -ETIMEDOUT; 2288c2ecf20Sopenharmony_ci } 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci if (loop_cnt > 50) { 2318c2ecf20Sopenharmony_ci retries_cnt++; 2328c2ecf20Sopenharmony_ci loop_cnt = 0; 2338c2ecf20Sopenharmony_ci udelay(10); 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci vc_bypass_value = voltdm->read(vc_bypass_val_reg); 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); 2398c2ecf20Sopenharmony_ci return 0; 2408c2ecf20Sopenharmony_ci} 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci/* Convert microsecond value to number of 32kHz clock cycles */ 2438c2ecf20Sopenharmony_cistatic inline u32 omap_usec_to_32k(u32 usec) 2448c2ecf20Sopenharmony_ci{ 2458c2ecf20Sopenharmony_ci return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL); 2468c2ecf20Sopenharmony_ci} 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_cistruct omap3_vc_timings { 2498c2ecf20Sopenharmony_ci u32 voltsetup1; 2508c2ecf20Sopenharmony_ci u32 voltsetup2; 2518c2ecf20Sopenharmony_ci}; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_cistruct omap3_vc { 2548c2ecf20Sopenharmony_ci struct voltagedomain *vd; 2558c2ecf20Sopenharmony_ci u32 voltctrl; 2568c2ecf20Sopenharmony_ci u32 voltsetup1; 2578c2ecf20Sopenharmony_ci u32 voltsetup2; 2588c2ecf20Sopenharmony_ci struct omap3_vc_timings timings[2]; 2598c2ecf20Sopenharmony_ci}; 2608c2ecf20Sopenharmony_cistatic struct omap3_vc vc; 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_civoid omap3_vc_set_pmic_signaling(int core_next_state) 2638c2ecf20Sopenharmony_ci{ 2648c2ecf20Sopenharmony_ci struct voltagedomain *vd = vc.vd; 2658c2ecf20Sopenharmony_ci struct omap3_vc_timings *c = vc.timings; 2668c2ecf20Sopenharmony_ci u32 voltctrl, voltsetup1, voltsetup2; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci voltctrl = vc.voltctrl; 2698c2ecf20Sopenharmony_ci voltsetup1 = vc.voltsetup1; 2708c2ecf20Sopenharmony_ci voltsetup2 = vc.voltsetup2; 2718c2ecf20Sopenharmony_ci 2728c2ecf20Sopenharmony_ci switch (core_next_state) { 2738c2ecf20Sopenharmony_ci case PWRDM_POWER_OFF: 2748c2ecf20Sopenharmony_ci voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_RET | 2758c2ecf20Sopenharmony_ci OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP); 2768c2ecf20Sopenharmony_ci voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_OFF; 2778c2ecf20Sopenharmony_ci if (voltctrl & OMAP3430_PRM_VOLTCTRL_SEL_OFF) 2788c2ecf20Sopenharmony_ci voltsetup2 = c->voltsetup2; 2798c2ecf20Sopenharmony_ci else 2808c2ecf20Sopenharmony_ci voltsetup1 = c->voltsetup1; 2818c2ecf20Sopenharmony_ci break; 2828c2ecf20Sopenharmony_ci case PWRDM_POWER_RET: 2838c2ecf20Sopenharmony_ci default: 2848c2ecf20Sopenharmony_ci c++; 2858c2ecf20Sopenharmony_ci voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_OFF | 2868c2ecf20Sopenharmony_ci OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP); 2878c2ecf20Sopenharmony_ci voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_RET; 2888c2ecf20Sopenharmony_ci voltsetup1 = c->voltsetup1; 2898c2ecf20Sopenharmony_ci break; 2908c2ecf20Sopenharmony_ci } 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_ci if (voltctrl != vc.voltctrl) { 2938c2ecf20Sopenharmony_ci vd->write(voltctrl, OMAP3_PRM_VOLTCTRL_OFFSET); 2948c2ecf20Sopenharmony_ci vc.voltctrl = voltctrl; 2958c2ecf20Sopenharmony_ci } 2968c2ecf20Sopenharmony_ci if (voltsetup1 != vc.voltsetup1) { 2978c2ecf20Sopenharmony_ci vd->write(c->voltsetup1, 2988c2ecf20Sopenharmony_ci OMAP3_PRM_VOLTSETUP1_OFFSET); 2998c2ecf20Sopenharmony_ci vc.voltsetup1 = voltsetup1; 3008c2ecf20Sopenharmony_ci } 3018c2ecf20Sopenharmony_ci if (voltsetup2 != vc.voltsetup2) { 3028c2ecf20Sopenharmony_ci vd->write(c->voltsetup2, 3038c2ecf20Sopenharmony_ci OMAP3_PRM_VOLTSETUP2_OFFSET); 3048c2ecf20Sopenharmony_ci vc.voltsetup2 = voltsetup2; 3058c2ecf20Sopenharmony_ci } 3068c2ecf20Sopenharmony_ci} 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_civoid omap4_vc_set_pmic_signaling(int core_next_state) 3098c2ecf20Sopenharmony_ci{ 3108c2ecf20Sopenharmony_ci struct voltagedomain *vd = vc.vd; 3118c2ecf20Sopenharmony_ci u32 val; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci if (!vd) 3148c2ecf20Sopenharmony_ci return; 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci switch (core_next_state) { 3178c2ecf20Sopenharmony_ci case PWRDM_POWER_RET: 3188c2ecf20Sopenharmony_ci val = OMAP4_VDD_RET_VAL; 3198c2ecf20Sopenharmony_ci break; 3208c2ecf20Sopenharmony_ci default: 3218c2ecf20Sopenharmony_ci val = OMAP4_VDD_DEFAULT_VAL; 3228c2ecf20Sopenharmony_ci break; 3238c2ecf20Sopenharmony_ci } 3248c2ecf20Sopenharmony_ci 3258c2ecf20Sopenharmony_ci vd->write(val, OMAP4_PRM_VOLTCTRL_OFFSET); 3268c2ecf20Sopenharmony_ci} 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci/* 3298c2ecf20Sopenharmony_ci * Configure signal polarity for sys_clkreq and sys_off_mode pins 3308c2ecf20Sopenharmony_ci * as the default values are wrong and can cause the system to hang 3318c2ecf20Sopenharmony_ci * if any twl4030 scripts are loaded. 3328c2ecf20Sopenharmony_ci */ 3338c2ecf20Sopenharmony_cistatic void __init omap3_vc_init_pmic_signaling(struct voltagedomain *voltdm) 3348c2ecf20Sopenharmony_ci{ 3358c2ecf20Sopenharmony_ci u32 val; 3368c2ecf20Sopenharmony_ci 3378c2ecf20Sopenharmony_ci if (vc.vd) 3388c2ecf20Sopenharmony_ci return; 3398c2ecf20Sopenharmony_ci 3408c2ecf20Sopenharmony_ci vc.vd = voltdm; 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ci val = voltdm->read(OMAP3_PRM_POLCTRL_OFFSET); 3438c2ecf20Sopenharmony_ci if (!(val & OMAP3430_PRM_POLCTRL_CLKREQ_POL) || 3448c2ecf20Sopenharmony_ci (val & OMAP3430_PRM_POLCTRL_OFFMODE_POL)) { 3458c2ecf20Sopenharmony_ci val |= OMAP3430_PRM_POLCTRL_CLKREQ_POL; 3468c2ecf20Sopenharmony_ci val &= ~OMAP3430_PRM_POLCTRL_OFFMODE_POL; 3478c2ecf20Sopenharmony_ci pr_debug("PM: fixing sys_clkreq and sys_off_mode polarity to 0x%x\n", 3488c2ecf20Sopenharmony_ci val); 3498c2ecf20Sopenharmony_ci voltdm->write(val, OMAP3_PRM_POLCTRL_OFFSET); 3508c2ecf20Sopenharmony_ci } 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci /* 3538c2ecf20Sopenharmony_ci * By default let's use I2C4 signaling for retention idle 3548c2ecf20Sopenharmony_ci * and sys_off_mode pin signaling for off idle. This way we 3558c2ecf20Sopenharmony_ci * have sys_clk_req pin go down for retention and both 3568c2ecf20Sopenharmony_ci * sys_clk_req and sys_off_mode pins will go down for off 3578c2ecf20Sopenharmony_ci * idle. And we can also scale voltages to zero for off-idle. 3588c2ecf20Sopenharmony_ci * Note that no actual voltage scaling during off-idle will 3598c2ecf20Sopenharmony_ci * happen unless the board specific twl4030 PMIC scripts are 3608c2ecf20Sopenharmony_ci * loaded. See also omap_vc_i2c_init for comments regarding 3618c2ecf20Sopenharmony_ci * erratum i531. 3628c2ecf20Sopenharmony_ci */ 3638c2ecf20Sopenharmony_ci val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); 3648c2ecf20Sopenharmony_ci if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) { 3658c2ecf20Sopenharmony_ci val |= OMAP3430_PRM_VOLTCTRL_SEL_OFF; 3668c2ecf20Sopenharmony_ci pr_debug("PM: setting voltctrl sys_off_mode signaling to 0x%x\n", 3678c2ecf20Sopenharmony_ci val); 3688c2ecf20Sopenharmony_ci voltdm->write(val, OMAP3_PRM_VOLTCTRL_OFFSET); 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci vc.voltctrl = val; 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci omap3_vc_set_pmic_signaling(PWRDM_POWER_ON); 3738c2ecf20Sopenharmony_ci} 3748c2ecf20Sopenharmony_ci 3758c2ecf20Sopenharmony_cistatic void omap3_init_voltsetup1(struct voltagedomain *voltdm, 3768c2ecf20Sopenharmony_ci struct omap3_vc_timings *c, u32 idle) 3778c2ecf20Sopenharmony_ci{ 3788c2ecf20Sopenharmony_ci unsigned long val; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci val = (voltdm->vc_param->on - idle) / voltdm->pmic->slew_rate; 3818c2ecf20Sopenharmony_ci val *= voltdm->sys_clk.rate / 8 / 1000000 + 1; 3828c2ecf20Sopenharmony_ci val <<= __ffs(voltdm->vfsm->voltsetup_mask); 3838c2ecf20Sopenharmony_ci c->voltsetup1 &= ~voltdm->vfsm->voltsetup_mask; 3848c2ecf20Sopenharmony_ci c->voltsetup1 |= val; 3858c2ecf20Sopenharmony_ci} 3868c2ecf20Sopenharmony_ci 3878c2ecf20Sopenharmony_ci/** 3888c2ecf20Sopenharmony_ci * omap3_set_i2c_timings - sets i2c sleep timings for a channel 3898c2ecf20Sopenharmony_ci * @voltdm: channel to configure 3908c2ecf20Sopenharmony_ci * @off_mode: select whether retention or off mode values used 3918c2ecf20Sopenharmony_ci * 3928c2ecf20Sopenharmony_ci * Calculates and sets up voltage controller to use I2C based 3938c2ecf20Sopenharmony_ci * voltage scaling for sleep modes. This can be used for either off mode 3948c2ecf20Sopenharmony_ci * or retention. Off mode has additionally an option to use sys_off_mode 3958c2ecf20Sopenharmony_ci * pad, which uses a global signal to program the whole power IC to 3968c2ecf20Sopenharmony_ci * off-mode. 3978c2ecf20Sopenharmony_ci * 3988c2ecf20Sopenharmony_ci * Note that pmic is not controlling the voltage scaling during 3998c2ecf20Sopenharmony_ci * retention signaled over I2C4, so we can keep voltsetup2 as 0. 4008c2ecf20Sopenharmony_ci * And the oscillator is not shut off over I2C4, so no need to 4018c2ecf20Sopenharmony_ci * set clksetup. 4028c2ecf20Sopenharmony_ci */ 4038c2ecf20Sopenharmony_cistatic void omap3_set_i2c_timings(struct voltagedomain *voltdm) 4048c2ecf20Sopenharmony_ci{ 4058c2ecf20Sopenharmony_ci struct omap3_vc_timings *c = vc.timings; 4068c2ecf20Sopenharmony_ci 4078c2ecf20Sopenharmony_ci /* Configure PRWDM_POWER_OFF over I2C4 */ 4088c2ecf20Sopenharmony_ci omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->off); 4098c2ecf20Sopenharmony_ci c++; 4108c2ecf20Sopenharmony_ci /* Configure PRWDM_POWER_RET over I2C4 */ 4118c2ecf20Sopenharmony_ci omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->ret); 4128c2ecf20Sopenharmony_ci} 4138c2ecf20Sopenharmony_ci 4148c2ecf20Sopenharmony_ci/** 4158c2ecf20Sopenharmony_ci * omap3_set_off_timings - sets off-mode timings for a channel 4168c2ecf20Sopenharmony_ci * @voltdm: channel to configure 4178c2ecf20Sopenharmony_ci * 4188c2ecf20Sopenharmony_ci * Calculates and sets up off-mode timings for a channel. Off-mode 4198c2ecf20Sopenharmony_ci * can use either I2C based voltage scaling, or alternatively 4208c2ecf20Sopenharmony_ci * sys_off_mode pad can be used to send a global command to power IC.n, 4218c2ecf20Sopenharmony_ci * sys_off_mode has the additional benefit that voltages can be 4228c2ecf20Sopenharmony_ci * scaled to zero volt level with TWL4030 / TWL5030, I2C can only 4238c2ecf20Sopenharmony_ci * scale to 600mV. 4248c2ecf20Sopenharmony_ci * 4258c2ecf20Sopenharmony_ci * Note that omap is not controlling the voltage scaling during 4268c2ecf20Sopenharmony_ci * off idle signaled by sys_off_mode, so we can keep voltsetup1 4278c2ecf20Sopenharmony_ci * as 0. 4288c2ecf20Sopenharmony_ci */ 4298c2ecf20Sopenharmony_cistatic void omap3_set_off_timings(struct voltagedomain *voltdm) 4308c2ecf20Sopenharmony_ci{ 4318c2ecf20Sopenharmony_ci struct omap3_vc_timings *c = vc.timings; 4328c2ecf20Sopenharmony_ci u32 tstart, tshut, clksetup, voltoffset; 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci if (c->voltsetup2) 4358c2ecf20Sopenharmony_ci return; 4368c2ecf20Sopenharmony_ci 4378c2ecf20Sopenharmony_ci omap_pm_get_oscillator(&tstart, &tshut); 4388c2ecf20Sopenharmony_ci if (tstart == ULONG_MAX) { 4398c2ecf20Sopenharmony_ci pr_debug("PM: oscillator start-up time not initialized, using 10ms\n"); 4408c2ecf20Sopenharmony_ci clksetup = omap_usec_to_32k(10000); 4418c2ecf20Sopenharmony_ci } else { 4428c2ecf20Sopenharmony_ci clksetup = omap_usec_to_32k(tstart); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci /* 4468c2ecf20Sopenharmony_ci * For twl4030 errata 27, we need to allow minimum ~488.32 us wait to 4478c2ecf20Sopenharmony_ci * switch from HFCLKIN to internal oscillator. That means timings 4488c2ecf20Sopenharmony_ci * have voltoffset fixed to 0xa in rounded up 32 KiHz cycles. And 4498c2ecf20Sopenharmony_ci * that means we can calculate the value based on the oscillator 4508c2ecf20Sopenharmony_ci * start-up time since voltoffset2 = clksetup - voltoffset. 4518c2ecf20Sopenharmony_ci */ 4528c2ecf20Sopenharmony_ci voltoffset = omap_usec_to_32k(488); 4538c2ecf20Sopenharmony_ci c->voltsetup2 = clksetup - voltoffset; 4548c2ecf20Sopenharmony_ci voltdm->write(clksetup, OMAP3_PRM_CLKSETUP_OFFSET); 4558c2ecf20Sopenharmony_ci voltdm->write(voltoffset, OMAP3_PRM_VOLTOFFSET_OFFSET); 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic void __init omap3_vc_init_channel(struct voltagedomain *voltdm) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci omap3_vc_init_pmic_signaling(voltdm); 4618c2ecf20Sopenharmony_ci omap3_set_off_timings(voltdm); 4628c2ecf20Sopenharmony_ci omap3_set_i2c_timings(voltdm); 4638c2ecf20Sopenharmony_ci} 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci/** 4668c2ecf20Sopenharmony_ci * omap4_calc_volt_ramp - calculates voltage ramping delays on omap4 4678c2ecf20Sopenharmony_ci * @voltdm: channel to calculate values for 4688c2ecf20Sopenharmony_ci * @voltage_diff: voltage difference in microvolts 4698c2ecf20Sopenharmony_ci * 4708c2ecf20Sopenharmony_ci * Calculates voltage ramp prescaler + counter values for a voltage 4718c2ecf20Sopenharmony_ci * difference on omap4. Returns a field value suitable for writing to 4728c2ecf20Sopenharmony_ci * VOLTSETUP register for a channel in following format: 4738c2ecf20Sopenharmony_ci * bits[8:9] prescaler ... bits[0:5] counter. See OMAP4 TRM for reference. 4748c2ecf20Sopenharmony_ci */ 4758c2ecf20Sopenharmony_cistatic u32 omap4_calc_volt_ramp(struct voltagedomain *voltdm, u32 voltage_diff) 4768c2ecf20Sopenharmony_ci{ 4778c2ecf20Sopenharmony_ci u32 prescaler; 4788c2ecf20Sopenharmony_ci u32 cycles; 4798c2ecf20Sopenharmony_ci u32 time; 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci time = voltage_diff / voltdm->pmic->slew_rate; 4828c2ecf20Sopenharmony_ci 4838c2ecf20Sopenharmony_ci cycles = voltdm->sys_clk.rate / 1000 * time / 1000; 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci cycles /= 64; 4868c2ecf20Sopenharmony_ci prescaler = 0; 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ci /* shift to next prescaler until no overflow */ 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* scale for div 256 = 64 * 4 */ 4918c2ecf20Sopenharmony_ci if (cycles > 63) { 4928c2ecf20Sopenharmony_ci cycles /= 4; 4938c2ecf20Sopenharmony_ci prescaler++; 4948c2ecf20Sopenharmony_ci } 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_ci /* scale for div 512 = 256 * 2 */ 4978c2ecf20Sopenharmony_ci if (cycles > 63) { 4988c2ecf20Sopenharmony_ci cycles /= 2; 4998c2ecf20Sopenharmony_ci prescaler++; 5008c2ecf20Sopenharmony_ci } 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* scale for div 2048 = 512 * 4 */ 5038c2ecf20Sopenharmony_ci if (cycles > 63) { 5048c2ecf20Sopenharmony_ci cycles /= 4; 5058c2ecf20Sopenharmony_ci prescaler++; 5068c2ecf20Sopenharmony_ci } 5078c2ecf20Sopenharmony_ci 5088c2ecf20Sopenharmony_ci /* check for overflow => invalid ramp time */ 5098c2ecf20Sopenharmony_ci if (cycles > 63) { 5108c2ecf20Sopenharmony_ci pr_warn("%s: invalid setuptime for vdd_%s\n", __func__, 5118c2ecf20Sopenharmony_ci voltdm->name); 5128c2ecf20Sopenharmony_ci return 0; 5138c2ecf20Sopenharmony_ci } 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci cycles++; 5168c2ecf20Sopenharmony_ci 5178c2ecf20Sopenharmony_ci return (prescaler << OMAP4430_RAMP_UP_PRESCAL_SHIFT) | 5188c2ecf20Sopenharmony_ci (cycles << OMAP4430_RAMP_UP_COUNT_SHIFT); 5198c2ecf20Sopenharmony_ci} 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci/** 5228c2ecf20Sopenharmony_ci * omap4_usec_to_val_scrm - convert microsecond value to SCRM module bitfield 5238c2ecf20Sopenharmony_ci * @usec: microseconds 5248c2ecf20Sopenharmony_ci * @shift: number of bits to shift left 5258c2ecf20Sopenharmony_ci * @mask: bitfield mask 5268c2ecf20Sopenharmony_ci * 5278c2ecf20Sopenharmony_ci * Converts microsecond value to OMAP4 SCRM bitfield. Bitfield is 5288c2ecf20Sopenharmony_ci * shifted to requested position, and checked agains the mask value. 5298c2ecf20Sopenharmony_ci * If larger, forced to the max value of the field (i.e. the mask itself.) 5308c2ecf20Sopenharmony_ci * Returns the SCRM bitfield value. 5318c2ecf20Sopenharmony_ci */ 5328c2ecf20Sopenharmony_cistatic u32 omap4_usec_to_val_scrm(u32 usec, int shift, u32 mask) 5338c2ecf20Sopenharmony_ci{ 5348c2ecf20Sopenharmony_ci u32 val; 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci val = omap_usec_to_32k(usec) << shift; 5378c2ecf20Sopenharmony_ci 5388c2ecf20Sopenharmony_ci /* Check for overflow, if yes, force to max value */ 5398c2ecf20Sopenharmony_ci if (val > mask) 5408c2ecf20Sopenharmony_ci val = mask; 5418c2ecf20Sopenharmony_ci 5428c2ecf20Sopenharmony_ci return val; 5438c2ecf20Sopenharmony_ci} 5448c2ecf20Sopenharmony_ci 5458c2ecf20Sopenharmony_ci/** 5468c2ecf20Sopenharmony_ci * omap4_set_timings - set voltage ramp timings for a channel 5478c2ecf20Sopenharmony_ci * @voltdm: channel to configure 5488c2ecf20Sopenharmony_ci * @off_mode: whether off-mode values are used 5498c2ecf20Sopenharmony_ci * 5508c2ecf20Sopenharmony_ci * Calculates and sets the voltage ramp up / down values for a channel. 5518c2ecf20Sopenharmony_ci */ 5528c2ecf20Sopenharmony_cistatic void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci u32 val; 5558c2ecf20Sopenharmony_ci u32 ramp; 5568c2ecf20Sopenharmony_ci int offset; 5578c2ecf20Sopenharmony_ci u32 tstart, tshut; 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci if (off_mode) { 5608c2ecf20Sopenharmony_ci ramp = omap4_calc_volt_ramp(voltdm, 5618c2ecf20Sopenharmony_ci voltdm->vc_param->on - voltdm->vc_param->off); 5628c2ecf20Sopenharmony_ci offset = voltdm->vfsm->voltsetup_off_reg; 5638c2ecf20Sopenharmony_ci } else { 5648c2ecf20Sopenharmony_ci ramp = omap4_calc_volt_ramp(voltdm, 5658c2ecf20Sopenharmony_ci voltdm->vc_param->on - voltdm->vc_param->ret); 5668c2ecf20Sopenharmony_ci offset = voltdm->vfsm->voltsetup_reg; 5678c2ecf20Sopenharmony_ci } 5688c2ecf20Sopenharmony_ci 5698c2ecf20Sopenharmony_ci if (!ramp) 5708c2ecf20Sopenharmony_ci return; 5718c2ecf20Sopenharmony_ci 5728c2ecf20Sopenharmony_ci val = voltdm->read(offset); 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci val |= ramp << OMAP4430_RAMP_DOWN_COUNT_SHIFT; 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci val |= ramp << OMAP4430_RAMP_UP_COUNT_SHIFT; 5778c2ecf20Sopenharmony_ci 5788c2ecf20Sopenharmony_ci voltdm->write(val, offset); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci omap_pm_get_oscillator(&tstart, &tshut); 5818c2ecf20Sopenharmony_ci 5828c2ecf20Sopenharmony_ci val = omap4_usec_to_val_scrm(tstart, OMAP4_SETUPTIME_SHIFT, 5838c2ecf20Sopenharmony_ci OMAP4_SETUPTIME_MASK); 5848c2ecf20Sopenharmony_ci val |= omap4_usec_to_val_scrm(tshut, OMAP4_DOWNTIME_SHIFT, 5858c2ecf20Sopenharmony_ci OMAP4_DOWNTIME_MASK); 5868c2ecf20Sopenharmony_ci 5878c2ecf20Sopenharmony_ci writel_relaxed(val, OMAP4_SCRM_CLKSETUPTIME); 5888c2ecf20Sopenharmony_ci} 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_cistatic void __init omap4_vc_init_pmic_signaling(struct voltagedomain *voltdm) 5918c2ecf20Sopenharmony_ci{ 5928c2ecf20Sopenharmony_ci if (vc.vd) 5938c2ecf20Sopenharmony_ci return; 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci vc.vd = voltdm; 5968c2ecf20Sopenharmony_ci voltdm->write(OMAP4_VDD_DEFAULT_VAL, OMAP4_PRM_VOLTCTRL_OFFSET); 5978c2ecf20Sopenharmony_ci} 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci/* OMAP4 specific voltage init functions */ 6008c2ecf20Sopenharmony_cistatic void __init omap4_vc_init_channel(struct voltagedomain *voltdm) 6018c2ecf20Sopenharmony_ci{ 6028c2ecf20Sopenharmony_ci omap4_vc_init_pmic_signaling(voltdm); 6038c2ecf20Sopenharmony_ci omap4_set_timings(voltdm, true); 6048c2ecf20Sopenharmony_ci omap4_set_timings(voltdm, false); 6058c2ecf20Sopenharmony_ci} 6068c2ecf20Sopenharmony_ci 6078c2ecf20Sopenharmony_cistruct i2c_init_data { 6088c2ecf20Sopenharmony_ci u8 loadbits; 6098c2ecf20Sopenharmony_ci u8 load; 6108c2ecf20Sopenharmony_ci u8 hsscll_38_4; 6118c2ecf20Sopenharmony_ci u8 hsscll_26; 6128c2ecf20Sopenharmony_ci u8 hsscll_19_2; 6138c2ecf20Sopenharmony_ci u8 hsscll_16_8; 6148c2ecf20Sopenharmony_ci u8 hsscll_12; 6158c2ecf20Sopenharmony_ci}; 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic const struct i2c_init_data omap4_i2c_timing_data[] __initconst = { 6188c2ecf20Sopenharmony_ci { 6198c2ecf20Sopenharmony_ci .load = 50, 6208c2ecf20Sopenharmony_ci .loadbits = 0x3, 6218c2ecf20Sopenharmony_ci .hsscll_38_4 = 13, 6228c2ecf20Sopenharmony_ci .hsscll_26 = 11, 6238c2ecf20Sopenharmony_ci .hsscll_19_2 = 9, 6248c2ecf20Sopenharmony_ci .hsscll_16_8 = 9, 6258c2ecf20Sopenharmony_ci .hsscll_12 = 8, 6268c2ecf20Sopenharmony_ci }, 6278c2ecf20Sopenharmony_ci { 6288c2ecf20Sopenharmony_ci .load = 25, 6298c2ecf20Sopenharmony_ci .loadbits = 0x2, 6308c2ecf20Sopenharmony_ci .hsscll_38_4 = 13, 6318c2ecf20Sopenharmony_ci .hsscll_26 = 11, 6328c2ecf20Sopenharmony_ci .hsscll_19_2 = 9, 6338c2ecf20Sopenharmony_ci .hsscll_16_8 = 9, 6348c2ecf20Sopenharmony_ci .hsscll_12 = 8, 6358c2ecf20Sopenharmony_ci }, 6368c2ecf20Sopenharmony_ci { 6378c2ecf20Sopenharmony_ci .load = 12, 6388c2ecf20Sopenharmony_ci .loadbits = 0x1, 6398c2ecf20Sopenharmony_ci .hsscll_38_4 = 11, 6408c2ecf20Sopenharmony_ci .hsscll_26 = 10, 6418c2ecf20Sopenharmony_ci .hsscll_19_2 = 9, 6428c2ecf20Sopenharmony_ci .hsscll_16_8 = 9, 6438c2ecf20Sopenharmony_ci .hsscll_12 = 8, 6448c2ecf20Sopenharmony_ci }, 6458c2ecf20Sopenharmony_ci { 6468c2ecf20Sopenharmony_ci .load = 0, 6478c2ecf20Sopenharmony_ci .loadbits = 0x0, 6488c2ecf20Sopenharmony_ci .hsscll_38_4 = 12, 6498c2ecf20Sopenharmony_ci .hsscll_26 = 10, 6508c2ecf20Sopenharmony_ci .hsscll_19_2 = 9, 6518c2ecf20Sopenharmony_ci .hsscll_16_8 = 8, 6528c2ecf20Sopenharmony_ci .hsscll_12 = 8, 6538c2ecf20Sopenharmony_ci }, 6548c2ecf20Sopenharmony_ci}; 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci/** 6578c2ecf20Sopenharmony_ci * omap4_vc_i2c_timing_init - sets up board I2C timing parameters 6588c2ecf20Sopenharmony_ci * @voltdm: voltagedomain pointer to get data from 6598c2ecf20Sopenharmony_ci * 6608c2ecf20Sopenharmony_ci * Use PMIC + board supplied settings for calculating the total I2C 6618c2ecf20Sopenharmony_ci * channel capacitance and set the timing parameters based on this. 6628c2ecf20Sopenharmony_ci * Pre-calculated values are provided in data tables, as it is not 6638c2ecf20Sopenharmony_ci * too straightforward to calculate these runtime. 6648c2ecf20Sopenharmony_ci */ 6658c2ecf20Sopenharmony_cistatic void __init omap4_vc_i2c_timing_init(struct voltagedomain *voltdm) 6668c2ecf20Sopenharmony_ci{ 6678c2ecf20Sopenharmony_ci u32 capacitance; 6688c2ecf20Sopenharmony_ci u32 val; 6698c2ecf20Sopenharmony_ci u16 hsscll; 6708c2ecf20Sopenharmony_ci const struct i2c_init_data *i2c_data; 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_ci if (!voltdm->pmic->i2c_high_speed) { 6738c2ecf20Sopenharmony_ci pr_info("%s: using bootloader low-speed timings\n", __func__); 6748c2ecf20Sopenharmony_ci return; 6758c2ecf20Sopenharmony_ci } 6768c2ecf20Sopenharmony_ci 6778c2ecf20Sopenharmony_ci /* PCB trace capacitance, 0.125pF / mm => mm / 8 */ 6788c2ecf20Sopenharmony_ci capacitance = DIV_ROUND_UP(sr_i2c_pcb_length, 8); 6798c2ecf20Sopenharmony_ci 6808c2ecf20Sopenharmony_ci /* OMAP pad capacitance */ 6818c2ecf20Sopenharmony_ci capacitance += 4; 6828c2ecf20Sopenharmony_ci 6838c2ecf20Sopenharmony_ci /* PMIC pad capacitance */ 6848c2ecf20Sopenharmony_ci capacitance += voltdm->pmic->i2c_pad_load; 6858c2ecf20Sopenharmony_ci 6868c2ecf20Sopenharmony_ci /* Search for capacitance match in the table */ 6878c2ecf20Sopenharmony_ci i2c_data = omap4_i2c_timing_data; 6888c2ecf20Sopenharmony_ci 6898c2ecf20Sopenharmony_ci while (i2c_data->load > capacitance) 6908c2ecf20Sopenharmony_ci i2c_data++; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* Select proper values based on sysclk frequency */ 6938c2ecf20Sopenharmony_ci switch (voltdm->sys_clk.rate) { 6948c2ecf20Sopenharmony_ci case 38400000: 6958c2ecf20Sopenharmony_ci hsscll = i2c_data->hsscll_38_4; 6968c2ecf20Sopenharmony_ci break; 6978c2ecf20Sopenharmony_ci case 26000000: 6988c2ecf20Sopenharmony_ci hsscll = i2c_data->hsscll_26; 6998c2ecf20Sopenharmony_ci break; 7008c2ecf20Sopenharmony_ci case 19200000: 7018c2ecf20Sopenharmony_ci hsscll = i2c_data->hsscll_19_2; 7028c2ecf20Sopenharmony_ci break; 7038c2ecf20Sopenharmony_ci case 16800000: 7048c2ecf20Sopenharmony_ci hsscll = i2c_data->hsscll_16_8; 7058c2ecf20Sopenharmony_ci break; 7068c2ecf20Sopenharmony_ci case 12000000: 7078c2ecf20Sopenharmony_ci hsscll = i2c_data->hsscll_12; 7088c2ecf20Sopenharmony_ci break; 7098c2ecf20Sopenharmony_ci default: 7108c2ecf20Sopenharmony_ci pr_warn("%s: unsupported sysclk rate: %d!\n", __func__, 7118c2ecf20Sopenharmony_ci voltdm->sys_clk.rate); 7128c2ecf20Sopenharmony_ci return; 7138c2ecf20Sopenharmony_ci } 7148c2ecf20Sopenharmony_ci 7158c2ecf20Sopenharmony_ci /* Loadbits define pull setup for the I2C channels */ 7168c2ecf20Sopenharmony_ci val = i2c_data->loadbits << 25 | i2c_data->loadbits << 29; 7178c2ecf20Sopenharmony_ci 7188c2ecf20Sopenharmony_ci /* Write to SYSCTRL_PADCONF_WKUP_CTRL_I2C_2 to setup I2C pull */ 7198c2ecf20Sopenharmony_ci writel_relaxed(val, OMAP2_L4_IO_ADDRESS(OMAP4_CTRL_MODULE_PAD_WKUP + 7208c2ecf20Sopenharmony_ci OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2)); 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* HSSCLH can always be zero */ 7238c2ecf20Sopenharmony_ci val = hsscll << OMAP4430_HSSCLL_SHIFT; 7248c2ecf20Sopenharmony_ci val |= (0x28 << OMAP4430_SCLL_SHIFT | 0x2c << OMAP4430_SCLH_SHIFT); 7258c2ecf20Sopenharmony_ci 7268c2ecf20Sopenharmony_ci /* Write setup times to I2C config register */ 7278c2ecf20Sopenharmony_ci voltdm->write(val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); 7288c2ecf20Sopenharmony_ci} 7298c2ecf20Sopenharmony_ci 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci 7328c2ecf20Sopenharmony_ci/** 7338c2ecf20Sopenharmony_ci * omap_vc_i2c_init - initialize I2C interface to PMIC 7348c2ecf20Sopenharmony_ci * @voltdm: voltage domain containing VC data 7358c2ecf20Sopenharmony_ci * 7368c2ecf20Sopenharmony_ci * Use PMIC supplied settings for I2C high-speed mode and 7378c2ecf20Sopenharmony_ci * master code (if set) and program the VC I2C configuration 7388c2ecf20Sopenharmony_ci * register. 7398c2ecf20Sopenharmony_ci * 7408c2ecf20Sopenharmony_ci * The VC I2C configuration is common to all VC channels, 7418c2ecf20Sopenharmony_ci * so this function only configures I2C for the first VC 7428c2ecf20Sopenharmony_ci * channel registers. All other VC channels will use the 7438c2ecf20Sopenharmony_ci * same configuration. 7448c2ecf20Sopenharmony_ci */ 7458c2ecf20Sopenharmony_cistatic void __init omap_vc_i2c_init(struct voltagedomain *voltdm) 7468c2ecf20Sopenharmony_ci{ 7478c2ecf20Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 7488c2ecf20Sopenharmony_ci static bool initialized; 7498c2ecf20Sopenharmony_ci static bool i2c_high_speed; 7508c2ecf20Sopenharmony_ci u8 mcode; 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci if (initialized) { 7538c2ecf20Sopenharmony_ci if (voltdm->pmic->i2c_high_speed != i2c_high_speed) 7548c2ecf20Sopenharmony_ci pr_warn("%s: I2C config for vdd_%s does not match other channels (%u).\n", 7558c2ecf20Sopenharmony_ci __func__, voltdm->name, i2c_high_speed); 7568c2ecf20Sopenharmony_ci return; 7578c2ecf20Sopenharmony_ci } 7588c2ecf20Sopenharmony_ci 7598c2ecf20Sopenharmony_ci /* 7608c2ecf20Sopenharmony_ci * Note that for omap3 OMAP3430_SREN_MASK clears SREN to work around 7618c2ecf20Sopenharmony_ci * erratum i531 "Extra Power Consumed When Repeated Start Operation 7628c2ecf20Sopenharmony_ci * Mode Is Enabled on I2C Interface Dedicated for Smart Reflex (I2C4)". 7638c2ecf20Sopenharmony_ci * Otherwise I2C4 eventually leads into about 23mW extra power being 7648c2ecf20Sopenharmony_ci * consumed even during off idle using VMODE. 7658c2ecf20Sopenharmony_ci */ 7668c2ecf20Sopenharmony_ci i2c_high_speed = voltdm->pmic->i2c_high_speed; 7678c2ecf20Sopenharmony_ci if (i2c_high_speed) 7688c2ecf20Sopenharmony_ci voltdm->rmw(vc->common->i2c_cfg_clear_mask, 7698c2ecf20Sopenharmony_ci vc->common->i2c_cfg_hsen_mask, 7708c2ecf20Sopenharmony_ci vc->common->i2c_cfg_reg); 7718c2ecf20Sopenharmony_ci 7728c2ecf20Sopenharmony_ci mcode = voltdm->pmic->i2c_mcode; 7738c2ecf20Sopenharmony_ci if (mcode) 7748c2ecf20Sopenharmony_ci voltdm->rmw(vc->common->i2c_mcode_mask, 7758c2ecf20Sopenharmony_ci mcode << __ffs(vc->common->i2c_mcode_mask), 7768c2ecf20Sopenharmony_ci vc->common->i2c_cfg_reg); 7778c2ecf20Sopenharmony_ci 7788c2ecf20Sopenharmony_ci if (cpu_is_omap44xx()) 7798c2ecf20Sopenharmony_ci omap4_vc_i2c_timing_init(voltdm); 7808c2ecf20Sopenharmony_ci 7818c2ecf20Sopenharmony_ci initialized = true; 7828c2ecf20Sopenharmony_ci} 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_ci/** 7858c2ecf20Sopenharmony_ci * omap_vc_calc_vsel - calculate vsel value for a channel 7868c2ecf20Sopenharmony_ci * @voltdm: channel to calculate value for 7878c2ecf20Sopenharmony_ci * @uvolt: microvolt value to convert to vsel 7888c2ecf20Sopenharmony_ci * 7898c2ecf20Sopenharmony_ci * Converts a microvolt value to vsel value for the used PMIC. 7908c2ecf20Sopenharmony_ci * This checks whether the microvolt value is out of bounds, and 7918c2ecf20Sopenharmony_ci * adjusts the value accordingly. If unsupported value detected, 7928c2ecf20Sopenharmony_ci * warning is thrown. 7938c2ecf20Sopenharmony_ci */ 7948c2ecf20Sopenharmony_cistatic u8 omap_vc_calc_vsel(struct voltagedomain *voltdm, u32 uvolt) 7958c2ecf20Sopenharmony_ci{ 7968c2ecf20Sopenharmony_ci if (voltdm->pmic->vddmin > uvolt) 7978c2ecf20Sopenharmony_ci uvolt = voltdm->pmic->vddmin; 7988c2ecf20Sopenharmony_ci if (voltdm->pmic->vddmax < uvolt) { 7998c2ecf20Sopenharmony_ci WARN(1, "%s: voltage not supported by pmic: %u vs max %u\n", 8008c2ecf20Sopenharmony_ci __func__, uvolt, voltdm->pmic->vddmax); 8018c2ecf20Sopenharmony_ci /* Lets try maximum value anyway */ 8028c2ecf20Sopenharmony_ci uvolt = voltdm->pmic->vddmax; 8038c2ecf20Sopenharmony_ci } 8048c2ecf20Sopenharmony_ci 8058c2ecf20Sopenharmony_ci return voltdm->pmic->uv_to_vsel(uvolt); 8068c2ecf20Sopenharmony_ci} 8078c2ecf20Sopenharmony_ci 8088c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 8098c2ecf20Sopenharmony_ci/** 8108c2ecf20Sopenharmony_ci * omap_pm_setup_sr_i2c_pcb_length - set length of SR I2C traces on PCB 8118c2ecf20Sopenharmony_ci * @mm: length of the PCB trace in millimetres 8128c2ecf20Sopenharmony_ci * 8138c2ecf20Sopenharmony_ci * Sets the PCB trace length for the I2C channel. By default uses 63mm. 8148c2ecf20Sopenharmony_ci * This is needed for properly calculating the capacitance value for 8158c2ecf20Sopenharmony_ci * the PCB trace, and for setting the SR I2C channel timing parameters. 8168c2ecf20Sopenharmony_ci */ 8178c2ecf20Sopenharmony_civoid __init omap_pm_setup_sr_i2c_pcb_length(u32 mm) 8188c2ecf20Sopenharmony_ci{ 8198c2ecf20Sopenharmony_ci sr_i2c_pcb_length = mm; 8208c2ecf20Sopenharmony_ci} 8218c2ecf20Sopenharmony_ci#endif 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_civoid __init omap_vc_init_channel(struct voltagedomain *voltdm) 8248c2ecf20Sopenharmony_ci{ 8258c2ecf20Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 8268c2ecf20Sopenharmony_ci u8 on_vsel, onlp_vsel, ret_vsel, off_vsel; 8278c2ecf20Sopenharmony_ci u32 val; 8288c2ecf20Sopenharmony_ci 8298c2ecf20Sopenharmony_ci if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) { 8308c2ecf20Sopenharmony_ci pr_err("%s: No PMIC info for vdd_%s\n", __func__, voltdm->name); 8318c2ecf20Sopenharmony_ci return; 8328c2ecf20Sopenharmony_ci } 8338c2ecf20Sopenharmony_ci 8348c2ecf20Sopenharmony_ci if (!voltdm->read || !voltdm->write) { 8358c2ecf20Sopenharmony_ci pr_err("%s: No read/write API for accessing vdd_%s regs\n", 8368c2ecf20Sopenharmony_ci __func__, voltdm->name); 8378c2ecf20Sopenharmony_ci return; 8388c2ecf20Sopenharmony_ci } 8398c2ecf20Sopenharmony_ci 8408c2ecf20Sopenharmony_ci vc->cfg_channel = 0; 8418c2ecf20Sopenharmony_ci if (vc->flags & OMAP_VC_CHANNEL_CFG_MUTANT) 8428c2ecf20Sopenharmony_ci vc_cfg_bits = &vc_mutant_channel_cfg; 8438c2ecf20Sopenharmony_ci else 8448c2ecf20Sopenharmony_ci vc_cfg_bits = &vc_default_channel_cfg; 8458c2ecf20Sopenharmony_ci 8468c2ecf20Sopenharmony_ci /* get PMIC/board specific settings */ 8478c2ecf20Sopenharmony_ci vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr; 8488c2ecf20Sopenharmony_ci vc->volt_reg_addr = voltdm->pmic->volt_reg_addr; 8498c2ecf20Sopenharmony_ci vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr; 8508c2ecf20Sopenharmony_ci 8518c2ecf20Sopenharmony_ci /* Configure the i2c slave address for this VC */ 8528c2ecf20Sopenharmony_ci voltdm->rmw(vc->smps_sa_mask, 8538c2ecf20Sopenharmony_ci vc->i2c_slave_addr << __ffs(vc->smps_sa_mask), 8548c2ecf20Sopenharmony_ci vc->smps_sa_reg); 8558c2ecf20Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->sa; 8568c2ecf20Sopenharmony_ci 8578c2ecf20Sopenharmony_ci /* 8588c2ecf20Sopenharmony_ci * Configure the PMIC register addresses. 8598c2ecf20Sopenharmony_ci */ 8608c2ecf20Sopenharmony_ci voltdm->rmw(vc->smps_volra_mask, 8618c2ecf20Sopenharmony_ci vc->volt_reg_addr << __ffs(vc->smps_volra_mask), 8628c2ecf20Sopenharmony_ci vc->smps_volra_reg); 8638c2ecf20Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->rav; 8648c2ecf20Sopenharmony_ci 8658c2ecf20Sopenharmony_ci if (vc->cmd_reg_addr) { 8668c2ecf20Sopenharmony_ci voltdm->rmw(vc->smps_cmdra_mask, 8678c2ecf20Sopenharmony_ci vc->cmd_reg_addr << __ffs(vc->smps_cmdra_mask), 8688c2ecf20Sopenharmony_ci vc->smps_cmdra_reg); 8698c2ecf20Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->rac; 8708c2ecf20Sopenharmony_ci } 8718c2ecf20Sopenharmony_ci 8728c2ecf20Sopenharmony_ci if (vc->cmd_reg_addr == vc->volt_reg_addr) 8738c2ecf20Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->racen; 8748c2ecf20Sopenharmony_ci 8758c2ecf20Sopenharmony_ci /* Set up the on, inactive, retention and off voltage */ 8768c2ecf20Sopenharmony_ci on_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->on); 8778c2ecf20Sopenharmony_ci onlp_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->onlp); 8788c2ecf20Sopenharmony_ci ret_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->ret); 8798c2ecf20Sopenharmony_ci off_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->off); 8808c2ecf20Sopenharmony_ci 8818c2ecf20Sopenharmony_ci val = ((on_vsel << vc->common->cmd_on_shift) | 8828c2ecf20Sopenharmony_ci (onlp_vsel << vc->common->cmd_onlp_shift) | 8838c2ecf20Sopenharmony_ci (ret_vsel << vc->common->cmd_ret_shift) | 8848c2ecf20Sopenharmony_ci (off_vsel << vc->common->cmd_off_shift)); 8858c2ecf20Sopenharmony_ci voltdm->write(val, vc->cmdval_reg); 8868c2ecf20Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->cmd; 8878c2ecf20Sopenharmony_ci 8888c2ecf20Sopenharmony_ci /* Channel configuration */ 8898c2ecf20Sopenharmony_ci omap_vc_config_channel(voltdm); 8908c2ecf20Sopenharmony_ci 8918c2ecf20Sopenharmony_ci omap_vc_i2c_init(voltdm); 8928c2ecf20Sopenharmony_ci 8938c2ecf20Sopenharmony_ci if (cpu_is_omap34xx()) 8948c2ecf20Sopenharmony_ci omap3_vc_init_channel(voltdm); 8958c2ecf20Sopenharmony_ci else if (cpu_is_omap44xx()) 8968c2ecf20Sopenharmony_ci omap4_vc_init_channel(voltdm); 8978c2ecf20Sopenharmony_ci} 8988c2ecf20Sopenharmony_ci 899