162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * OMAP Voltage Controller (VC) interface 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2011 Texas Instruments, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/kernel.h> 862306a36Sopenharmony_ci#include <linux/delay.h> 962306a36Sopenharmony_ci#include <linux/init.h> 1062306a36Sopenharmony_ci#include <linux/bug.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/div64.h> 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci#include "iomap.h" 1662306a36Sopenharmony_ci#include "soc.h" 1762306a36Sopenharmony_ci#include "voltage.h" 1862306a36Sopenharmony_ci#include "vc.h" 1962306a36Sopenharmony_ci#include "prm-regbits-34xx.h" 2062306a36Sopenharmony_ci#include "prm-regbits-44xx.h" 2162306a36Sopenharmony_ci#include "prm44xx.h" 2262306a36Sopenharmony_ci#include "pm.h" 2362306a36Sopenharmony_ci#include "scrm44xx.h" 2462306a36Sopenharmony_ci#include "control.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#define OMAP4430_VDD_IVA_I2C_DISABLE BIT(14) 2762306a36Sopenharmony_ci#define OMAP4430_VDD_MPU_I2C_DISABLE BIT(13) 2862306a36Sopenharmony_ci#define OMAP4430_VDD_CORE_I2C_DISABLE BIT(12) 2962306a36Sopenharmony_ci#define OMAP4430_VDD_IVA_PRESENCE BIT(9) 3062306a36Sopenharmony_ci#define OMAP4430_VDD_MPU_PRESENCE BIT(8) 3162306a36Sopenharmony_ci#define OMAP4430_AUTO_CTRL_VDD_IVA(x) ((x) << 4) 3262306a36Sopenharmony_ci#define OMAP4430_AUTO_CTRL_VDD_MPU(x) ((x) << 2) 3362306a36Sopenharmony_ci#define OMAP4430_AUTO_CTRL_VDD_CORE(x) ((x) << 0) 3462306a36Sopenharmony_ci#define OMAP4430_AUTO_CTRL_VDD_RET 2 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci#define OMAP4430_VDD_I2C_DISABLE_MASK \ 3762306a36Sopenharmony_ci (OMAP4430_VDD_IVA_I2C_DISABLE | \ 3862306a36Sopenharmony_ci OMAP4430_VDD_MPU_I2C_DISABLE | \ 3962306a36Sopenharmony_ci OMAP4430_VDD_CORE_I2C_DISABLE) 4062306a36Sopenharmony_ci 4162306a36Sopenharmony_ci#define OMAP4_VDD_DEFAULT_VAL \ 4262306a36Sopenharmony_ci (OMAP4430_VDD_I2C_DISABLE_MASK | \ 4362306a36Sopenharmony_ci OMAP4430_VDD_IVA_PRESENCE | OMAP4430_VDD_MPU_PRESENCE | \ 4462306a36Sopenharmony_ci OMAP4430_AUTO_CTRL_VDD_IVA(OMAP4430_AUTO_CTRL_VDD_RET) | \ 4562306a36Sopenharmony_ci OMAP4430_AUTO_CTRL_VDD_MPU(OMAP4430_AUTO_CTRL_VDD_RET) | \ 4662306a36Sopenharmony_ci OMAP4430_AUTO_CTRL_VDD_CORE(OMAP4430_AUTO_CTRL_VDD_RET)) 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define OMAP4_VDD_RET_VAL \ 4962306a36Sopenharmony_ci (OMAP4_VDD_DEFAULT_VAL & ~OMAP4430_VDD_I2C_DISABLE_MASK) 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci/** 5262306a36Sopenharmony_ci * struct omap_vc_channel_cfg - describe the cfg_channel bitfield 5362306a36Sopenharmony_ci * @sa: bit for slave address 5462306a36Sopenharmony_ci * @rav: bit for voltage configuration register 5562306a36Sopenharmony_ci * @rac: bit for command configuration register 5662306a36Sopenharmony_ci * @racen: enable bit for RAC 5762306a36Sopenharmony_ci * @cmd: bit for command value set selection 5862306a36Sopenharmony_ci * 5962306a36Sopenharmony_ci * Channel configuration bits, common for OMAP3+ 6062306a36Sopenharmony_ci * OMAP3 register: PRM_VC_CH_CONF 6162306a36Sopenharmony_ci * OMAP4 register: PRM_VC_CFG_CHANNEL 6262306a36Sopenharmony_ci * OMAP5 register: PRM_VC_SMPS_<voltdm>_CONFIG 6362306a36Sopenharmony_ci */ 6462306a36Sopenharmony_cistruct omap_vc_channel_cfg { 6562306a36Sopenharmony_ci u8 sa; 6662306a36Sopenharmony_ci u8 rav; 6762306a36Sopenharmony_ci u8 rac; 6862306a36Sopenharmony_ci u8 racen; 6962306a36Sopenharmony_ci u8 cmd; 7062306a36Sopenharmony_ci}; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_cistatic struct omap_vc_channel_cfg vc_default_channel_cfg = { 7362306a36Sopenharmony_ci .sa = BIT(0), 7462306a36Sopenharmony_ci .rav = BIT(1), 7562306a36Sopenharmony_ci .rac = BIT(2), 7662306a36Sopenharmony_ci .racen = BIT(3), 7762306a36Sopenharmony_ci .cmd = BIT(4), 7862306a36Sopenharmony_ci}; 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci/* 8162306a36Sopenharmony_ci * On OMAP3+, all VC channels have the above default bitfield 8262306a36Sopenharmony_ci * configuration, except the OMAP4 MPU channel. This appears 8362306a36Sopenharmony_ci * to be a freak accident as every other VC channel has the 8462306a36Sopenharmony_ci * default configuration, thus creating a mutant channel config. 8562306a36Sopenharmony_ci */ 8662306a36Sopenharmony_cistatic struct omap_vc_channel_cfg vc_mutant_channel_cfg = { 8762306a36Sopenharmony_ci .sa = BIT(0), 8862306a36Sopenharmony_ci .rav = BIT(2), 8962306a36Sopenharmony_ci .rac = BIT(3), 9062306a36Sopenharmony_ci .racen = BIT(4), 9162306a36Sopenharmony_ci .cmd = BIT(1), 9262306a36Sopenharmony_ci}; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_cistatic struct omap_vc_channel_cfg *vc_cfg_bits; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci/* Default I2C trace length on pcb, 6.3cm. Used for capacitance calculations. */ 9762306a36Sopenharmony_cistatic u32 sr_i2c_pcb_length = 63; 9862306a36Sopenharmony_ci#define CFG_CHANNEL_MASK 0x1f 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/** 10162306a36Sopenharmony_ci * omap_vc_config_channel - configure VC channel to PMIC mappings 10262306a36Sopenharmony_ci * @voltdm: pointer to voltagdomain defining the desired VC channel 10362306a36Sopenharmony_ci * 10462306a36Sopenharmony_ci * Configures the VC channel to PMIC mappings for the following 10562306a36Sopenharmony_ci * PMIC settings 10662306a36Sopenharmony_ci * - i2c slave address (SA) 10762306a36Sopenharmony_ci * - voltage configuration address (RAV) 10862306a36Sopenharmony_ci * - command configuration address (RAC) and enable bit (RACEN) 10962306a36Sopenharmony_ci * - command values for ON, ONLP, RET and OFF (CMD) 11062306a36Sopenharmony_ci * 11162306a36Sopenharmony_ci * This function currently only allows flexible configuration of the 11262306a36Sopenharmony_ci * non-default channel. Starting with OMAP4, there are more than 2 11362306a36Sopenharmony_ci * channels, with one defined as the default (on OMAP4, it's MPU.) 11462306a36Sopenharmony_ci * Only the non-default channel can be configured. 11562306a36Sopenharmony_ci */ 11662306a36Sopenharmony_cistatic int omap_vc_config_channel(struct voltagedomain *voltdm) 11762306a36Sopenharmony_ci{ 11862306a36Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci /* 12162306a36Sopenharmony_ci * For default channel, the only configurable bit is RACEN. 12262306a36Sopenharmony_ci * All others must stay at zero (see function comment above.) 12362306a36Sopenharmony_ci */ 12462306a36Sopenharmony_ci if (vc->flags & OMAP_VC_CHANNEL_DEFAULT) 12562306a36Sopenharmony_ci vc->cfg_channel &= vc_cfg_bits->racen; 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci voltdm->rmw(CFG_CHANNEL_MASK << vc->cfg_channel_sa_shift, 12862306a36Sopenharmony_ci vc->cfg_channel << vc->cfg_channel_sa_shift, 12962306a36Sopenharmony_ci vc->cfg_channel_reg); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci return 0; 13262306a36Sopenharmony_ci} 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci/* Voltage scale and accessory APIs */ 13562306a36Sopenharmony_ciint omap_vc_pre_scale(struct voltagedomain *voltdm, 13662306a36Sopenharmony_ci unsigned long target_volt, 13762306a36Sopenharmony_ci u8 *target_vsel, u8 *current_vsel) 13862306a36Sopenharmony_ci{ 13962306a36Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 14062306a36Sopenharmony_ci u32 vc_cmdval; 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci /* Check if sufficient pmic info is available for this vdd */ 14362306a36Sopenharmony_ci if (!voltdm->pmic) { 14462306a36Sopenharmony_ci pr_err("%s: Insufficient pmic info to scale the vdd_%s\n", 14562306a36Sopenharmony_ci __func__, voltdm->name); 14662306a36Sopenharmony_ci return -EINVAL; 14762306a36Sopenharmony_ci } 14862306a36Sopenharmony_ci 14962306a36Sopenharmony_ci if (!voltdm->pmic->uv_to_vsel) { 15062306a36Sopenharmony_ci pr_err("%s: PMIC function to convert voltage in uV to vsel not registered. Hence unable to scale voltage for vdd_%s\n", 15162306a36Sopenharmony_ci __func__, voltdm->name); 15262306a36Sopenharmony_ci return -ENODATA; 15362306a36Sopenharmony_ci } 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (!voltdm->read || !voltdm->write) { 15662306a36Sopenharmony_ci pr_err("%s: No read/write API for accessing vdd_%s regs\n", 15762306a36Sopenharmony_ci __func__, voltdm->name); 15862306a36Sopenharmony_ci return -EINVAL; 15962306a36Sopenharmony_ci } 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ci *target_vsel = voltdm->pmic->uv_to_vsel(target_volt); 16262306a36Sopenharmony_ci *current_vsel = voltdm->pmic->uv_to_vsel(voltdm->nominal_volt); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci /* Setting the ON voltage to the new target voltage */ 16562306a36Sopenharmony_ci vc_cmdval = voltdm->read(vc->cmdval_reg); 16662306a36Sopenharmony_ci vc_cmdval &= ~vc->common->cmd_on_mask; 16762306a36Sopenharmony_ci vc_cmdval |= (*target_vsel << vc->common->cmd_on_shift); 16862306a36Sopenharmony_ci voltdm->write(vc_cmdval, vc->cmdval_reg); 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci voltdm->vc_param->on = target_volt; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci omap_vp_update_errorgain(voltdm, target_volt); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_civoid omap_vc_post_scale(struct voltagedomain *voltdm, 17862306a36Sopenharmony_ci unsigned long target_volt, 17962306a36Sopenharmony_ci u8 target_vsel, u8 current_vsel) 18062306a36Sopenharmony_ci{ 18162306a36Sopenharmony_ci u32 smps_steps = 0, smps_delay = 0; 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci smps_steps = abs(target_vsel - current_vsel); 18462306a36Sopenharmony_ci /* SMPS slew rate / step size. 2us added as buffer. */ 18562306a36Sopenharmony_ci smps_delay = ((smps_steps * voltdm->pmic->step_size) / 18662306a36Sopenharmony_ci voltdm->pmic->slew_rate) + 2; 18762306a36Sopenharmony_ci udelay(smps_delay); 18862306a36Sopenharmony_ci} 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci/* vc_bypass_scale - VC bypass method of voltage scaling */ 19162306a36Sopenharmony_ciint omap_vc_bypass_scale(struct voltagedomain *voltdm, 19262306a36Sopenharmony_ci unsigned long target_volt) 19362306a36Sopenharmony_ci{ 19462306a36Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 19562306a36Sopenharmony_ci u32 loop_cnt = 0, retries_cnt = 0; 19662306a36Sopenharmony_ci u32 vc_valid, vc_bypass_val_reg, vc_bypass_value; 19762306a36Sopenharmony_ci u8 target_vsel, current_vsel; 19862306a36Sopenharmony_ci int ret; 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci ret = omap_vc_pre_scale(voltdm, target_volt, &target_vsel, ¤t_vsel); 20162306a36Sopenharmony_ci if (ret) 20262306a36Sopenharmony_ci return ret; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci vc_valid = vc->common->valid; 20562306a36Sopenharmony_ci vc_bypass_val_reg = vc->common->bypass_val_reg; 20662306a36Sopenharmony_ci vc_bypass_value = (target_vsel << vc->common->data_shift) | 20762306a36Sopenharmony_ci (vc->volt_reg_addr << vc->common->regaddr_shift) | 20862306a36Sopenharmony_ci (vc->i2c_slave_addr << vc->common->slaveaddr_shift); 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci voltdm->write(vc_bypass_value, vc_bypass_val_reg); 21162306a36Sopenharmony_ci voltdm->write(vc_bypass_value | vc_valid, vc_bypass_val_reg); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci vc_bypass_value = voltdm->read(vc_bypass_val_reg); 21462306a36Sopenharmony_ci /* 21562306a36Sopenharmony_ci * Loop till the bypass command is acknowledged from the SMPS. 21662306a36Sopenharmony_ci * NOTE: This is legacy code. The loop count and retry count needs 21762306a36Sopenharmony_ci * to be revisited. 21862306a36Sopenharmony_ci */ 21962306a36Sopenharmony_ci while (!(vc_bypass_value & vc_valid)) { 22062306a36Sopenharmony_ci loop_cnt++; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci if (retries_cnt > 10) { 22362306a36Sopenharmony_ci pr_warn("%s: Retry count exceeded\n", __func__); 22462306a36Sopenharmony_ci return -ETIMEDOUT; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci if (loop_cnt > 50) { 22862306a36Sopenharmony_ci retries_cnt++; 22962306a36Sopenharmony_ci loop_cnt = 0; 23062306a36Sopenharmony_ci udelay(10); 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci vc_bypass_value = voltdm->read(vc_bypass_val_reg); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci omap_vc_post_scale(voltdm, target_volt, target_vsel, current_vsel); 23662306a36Sopenharmony_ci return 0; 23762306a36Sopenharmony_ci} 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci/* Convert microsecond value to number of 32kHz clock cycles */ 24062306a36Sopenharmony_cistatic inline u32 omap_usec_to_32k(u32 usec) 24162306a36Sopenharmony_ci{ 24262306a36Sopenharmony_ci return DIV_ROUND_UP_ULL(32768ULL * (u64)usec, 1000000ULL); 24362306a36Sopenharmony_ci} 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_cistruct omap3_vc_timings { 24662306a36Sopenharmony_ci u32 voltsetup1; 24762306a36Sopenharmony_ci u32 voltsetup2; 24862306a36Sopenharmony_ci}; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_cistruct omap3_vc { 25162306a36Sopenharmony_ci struct voltagedomain *vd; 25262306a36Sopenharmony_ci u32 voltctrl; 25362306a36Sopenharmony_ci u32 voltsetup1; 25462306a36Sopenharmony_ci u32 voltsetup2; 25562306a36Sopenharmony_ci struct omap3_vc_timings timings[2]; 25662306a36Sopenharmony_ci}; 25762306a36Sopenharmony_cistatic struct omap3_vc vc; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_civoid omap3_vc_set_pmic_signaling(int core_next_state) 26062306a36Sopenharmony_ci{ 26162306a36Sopenharmony_ci struct voltagedomain *vd = vc.vd; 26262306a36Sopenharmony_ci struct omap3_vc_timings *c = vc.timings; 26362306a36Sopenharmony_ci u32 voltctrl, voltsetup1, voltsetup2; 26462306a36Sopenharmony_ci 26562306a36Sopenharmony_ci voltctrl = vc.voltctrl; 26662306a36Sopenharmony_ci voltsetup1 = vc.voltsetup1; 26762306a36Sopenharmony_ci voltsetup2 = vc.voltsetup2; 26862306a36Sopenharmony_ci 26962306a36Sopenharmony_ci switch (core_next_state) { 27062306a36Sopenharmony_ci case PWRDM_POWER_OFF: 27162306a36Sopenharmony_ci voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_RET | 27262306a36Sopenharmony_ci OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP); 27362306a36Sopenharmony_ci voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_OFF; 27462306a36Sopenharmony_ci if (voltctrl & OMAP3430_PRM_VOLTCTRL_SEL_OFF) 27562306a36Sopenharmony_ci voltsetup2 = c->voltsetup2; 27662306a36Sopenharmony_ci else 27762306a36Sopenharmony_ci voltsetup1 = c->voltsetup1; 27862306a36Sopenharmony_ci break; 27962306a36Sopenharmony_ci case PWRDM_POWER_RET: 28062306a36Sopenharmony_ci default: 28162306a36Sopenharmony_ci c++; 28262306a36Sopenharmony_ci voltctrl &= ~(OMAP3430_PRM_VOLTCTRL_AUTO_OFF | 28362306a36Sopenharmony_ci OMAP3430_PRM_VOLTCTRL_AUTO_SLEEP); 28462306a36Sopenharmony_ci voltctrl |= OMAP3430_PRM_VOLTCTRL_AUTO_RET; 28562306a36Sopenharmony_ci voltsetup1 = c->voltsetup1; 28662306a36Sopenharmony_ci break; 28762306a36Sopenharmony_ci } 28862306a36Sopenharmony_ci 28962306a36Sopenharmony_ci if (voltctrl != vc.voltctrl) { 29062306a36Sopenharmony_ci vd->write(voltctrl, OMAP3_PRM_VOLTCTRL_OFFSET); 29162306a36Sopenharmony_ci vc.voltctrl = voltctrl; 29262306a36Sopenharmony_ci } 29362306a36Sopenharmony_ci if (voltsetup1 != vc.voltsetup1) { 29462306a36Sopenharmony_ci vd->write(c->voltsetup1, 29562306a36Sopenharmony_ci OMAP3_PRM_VOLTSETUP1_OFFSET); 29662306a36Sopenharmony_ci vc.voltsetup1 = voltsetup1; 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci if (voltsetup2 != vc.voltsetup2) { 29962306a36Sopenharmony_ci vd->write(c->voltsetup2, 30062306a36Sopenharmony_ci OMAP3_PRM_VOLTSETUP2_OFFSET); 30162306a36Sopenharmony_ci vc.voltsetup2 = voltsetup2; 30262306a36Sopenharmony_ci } 30362306a36Sopenharmony_ci} 30462306a36Sopenharmony_ci 30562306a36Sopenharmony_civoid omap4_vc_set_pmic_signaling(int core_next_state) 30662306a36Sopenharmony_ci{ 30762306a36Sopenharmony_ci struct voltagedomain *vd = vc.vd; 30862306a36Sopenharmony_ci u32 val; 30962306a36Sopenharmony_ci 31062306a36Sopenharmony_ci if (!vd) 31162306a36Sopenharmony_ci return; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci switch (core_next_state) { 31462306a36Sopenharmony_ci case PWRDM_POWER_RET: 31562306a36Sopenharmony_ci val = OMAP4_VDD_RET_VAL; 31662306a36Sopenharmony_ci break; 31762306a36Sopenharmony_ci default: 31862306a36Sopenharmony_ci val = OMAP4_VDD_DEFAULT_VAL; 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci } 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_ci vd->write(val, OMAP4_PRM_VOLTCTRL_OFFSET); 32362306a36Sopenharmony_ci} 32462306a36Sopenharmony_ci 32562306a36Sopenharmony_ci/* 32662306a36Sopenharmony_ci * Configure signal polarity for sys_clkreq and sys_off_mode pins 32762306a36Sopenharmony_ci * as the default values are wrong and can cause the system to hang 32862306a36Sopenharmony_ci * if any twl4030 scripts are loaded. 32962306a36Sopenharmony_ci */ 33062306a36Sopenharmony_cistatic void __init omap3_vc_init_pmic_signaling(struct voltagedomain *voltdm) 33162306a36Sopenharmony_ci{ 33262306a36Sopenharmony_ci u32 val; 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (vc.vd) 33562306a36Sopenharmony_ci return; 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci vc.vd = voltdm; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci val = voltdm->read(OMAP3_PRM_POLCTRL_OFFSET); 34062306a36Sopenharmony_ci if (!(val & OMAP3430_PRM_POLCTRL_CLKREQ_POL) || 34162306a36Sopenharmony_ci (val & OMAP3430_PRM_POLCTRL_OFFMODE_POL)) { 34262306a36Sopenharmony_ci val |= OMAP3430_PRM_POLCTRL_CLKREQ_POL; 34362306a36Sopenharmony_ci val &= ~OMAP3430_PRM_POLCTRL_OFFMODE_POL; 34462306a36Sopenharmony_ci pr_debug("PM: fixing sys_clkreq and sys_off_mode polarity to 0x%x\n", 34562306a36Sopenharmony_ci val); 34662306a36Sopenharmony_ci voltdm->write(val, OMAP3_PRM_POLCTRL_OFFSET); 34762306a36Sopenharmony_ci } 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci /* 35062306a36Sopenharmony_ci * By default let's use I2C4 signaling for retention idle 35162306a36Sopenharmony_ci * and sys_off_mode pin signaling for off idle. This way we 35262306a36Sopenharmony_ci * have sys_clk_req pin go down for retention and both 35362306a36Sopenharmony_ci * sys_clk_req and sys_off_mode pins will go down for off 35462306a36Sopenharmony_ci * idle. And we can also scale voltages to zero for off-idle. 35562306a36Sopenharmony_ci * Note that no actual voltage scaling during off-idle will 35662306a36Sopenharmony_ci * happen unless the board specific twl4030 PMIC scripts are 35762306a36Sopenharmony_ci * loaded. See also omap_vc_i2c_init for comments regarding 35862306a36Sopenharmony_ci * erratum i531. 35962306a36Sopenharmony_ci */ 36062306a36Sopenharmony_ci val = voltdm->read(OMAP3_PRM_VOLTCTRL_OFFSET); 36162306a36Sopenharmony_ci if (!(val & OMAP3430_PRM_VOLTCTRL_SEL_OFF)) { 36262306a36Sopenharmony_ci val |= OMAP3430_PRM_VOLTCTRL_SEL_OFF; 36362306a36Sopenharmony_ci pr_debug("PM: setting voltctrl sys_off_mode signaling to 0x%x\n", 36462306a36Sopenharmony_ci val); 36562306a36Sopenharmony_ci voltdm->write(val, OMAP3_PRM_VOLTCTRL_OFFSET); 36662306a36Sopenharmony_ci } 36762306a36Sopenharmony_ci vc.voltctrl = val; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci omap3_vc_set_pmic_signaling(PWRDM_POWER_ON); 37062306a36Sopenharmony_ci} 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cistatic void omap3_init_voltsetup1(struct voltagedomain *voltdm, 37362306a36Sopenharmony_ci struct omap3_vc_timings *c, u32 idle) 37462306a36Sopenharmony_ci{ 37562306a36Sopenharmony_ci unsigned long val; 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci val = (voltdm->vc_param->on - idle) / voltdm->pmic->slew_rate; 37862306a36Sopenharmony_ci val *= voltdm->sys_clk.rate / 8 / 1000000 + 1; 37962306a36Sopenharmony_ci val <<= __ffs(voltdm->vfsm->voltsetup_mask); 38062306a36Sopenharmony_ci c->voltsetup1 &= ~voltdm->vfsm->voltsetup_mask; 38162306a36Sopenharmony_ci c->voltsetup1 |= val; 38262306a36Sopenharmony_ci} 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci/** 38562306a36Sopenharmony_ci * omap3_set_i2c_timings - sets i2c sleep timings for a channel 38662306a36Sopenharmony_ci * @voltdm: channel to configure 38762306a36Sopenharmony_ci * @off_mode: select whether retention or off mode values used 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * Calculates and sets up voltage controller to use I2C based 39062306a36Sopenharmony_ci * voltage scaling for sleep modes. This can be used for either off mode 39162306a36Sopenharmony_ci * or retention. Off mode has additionally an option to use sys_off_mode 39262306a36Sopenharmony_ci * pad, which uses a global signal to program the whole power IC to 39362306a36Sopenharmony_ci * off-mode. 39462306a36Sopenharmony_ci * 39562306a36Sopenharmony_ci * Note that pmic is not controlling the voltage scaling during 39662306a36Sopenharmony_ci * retention signaled over I2C4, so we can keep voltsetup2 as 0. 39762306a36Sopenharmony_ci * And the oscillator is not shut off over I2C4, so no need to 39862306a36Sopenharmony_ci * set clksetup. 39962306a36Sopenharmony_ci */ 40062306a36Sopenharmony_cistatic void omap3_set_i2c_timings(struct voltagedomain *voltdm) 40162306a36Sopenharmony_ci{ 40262306a36Sopenharmony_ci struct omap3_vc_timings *c = vc.timings; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_ci /* Configure PRWDM_POWER_OFF over I2C4 */ 40562306a36Sopenharmony_ci omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->off); 40662306a36Sopenharmony_ci c++; 40762306a36Sopenharmony_ci /* Configure PRWDM_POWER_RET over I2C4 */ 40862306a36Sopenharmony_ci omap3_init_voltsetup1(voltdm, c, voltdm->vc_param->ret); 40962306a36Sopenharmony_ci} 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_ci/** 41262306a36Sopenharmony_ci * omap3_set_off_timings - sets off-mode timings for a channel 41362306a36Sopenharmony_ci * @voltdm: channel to configure 41462306a36Sopenharmony_ci * 41562306a36Sopenharmony_ci * Calculates and sets up off-mode timings for a channel. Off-mode 41662306a36Sopenharmony_ci * can use either I2C based voltage scaling, or alternatively 41762306a36Sopenharmony_ci * sys_off_mode pad can be used to send a global command to power IC.n, 41862306a36Sopenharmony_ci * sys_off_mode has the additional benefit that voltages can be 41962306a36Sopenharmony_ci * scaled to zero volt level with TWL4030 / TWL5030, I2C can only 42062306a36Sopenharmony_ci * scale to 600mV. 42162306a36Sopenharmony_ci * 42262306a36Sopenharmony_ci * Note that omap is not controlling the voltage scaling during 42362306a36Sopenharmony_ci * off idle signaled by sys_off_mode, so we can keep voltsetup1 42462306a36Sopenharmony_ci * as 0. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_cistatic void omap3_set_off_timings(struct voltagedomain *voltdm) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci struct omap3_vc_timings *c = vc.timings; 42962306a36Sopenharmony_ci u32 tstart, tshut, clksetup, voltoffset; 43062306a36Sopenharmony_ci 43162306a36Sopenharmony_ci if (c->voltsetup2) 43262306a36Sopenharmony_ci return; 43362306a36Sopenharmony_ci 43462306a36Sopenharmony_ci omap_pm_get_oscillator(&tstart, &tshut); 43562306a36Sopenharmony_ci if (tstart == ULONG_MAX) { 43662306a36Sopenharmony_ci pr_debug("PM: oscillator start-up time not initialized, using 10ms\n"); 43762306a36Sopenharmony_ci clksetup = omap_usec_to_32k(10000); 43862306a36Sopenharmony_ci } else { 43962306a36Sopenharmony_ci clksetup = omap_usec_to_32k(tstart); 44062306a36Sopenharmony_ci } 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci /* 44362306a36Sopenharmony_ci * For twl4030 errata 27, we need to allow minimum ~488.32 us wait to 44462306a36Sopenharmony_ci * switch from HFCLKIN to internal oscillator. That means timings 44562306a36Sopenharmony_ci * have voltoffset fixed to 0xa in rounded up 32 KiHz cycles. And 44662306a36Sopenharmony_ci * that means we can calculate the value based on the oscillator 44762306a36Sopenharmony_ci * start-up time since voltoffset2 = clksetup - voltoffset. 44862306a36Sopenharmony_ci */ 44962306a36Sopenharmony_ci voltoffset = omap_usec_to_32k(488); 45062306a36Sopenharmony_ci c->voltsetup2 = clksetup - voltoffset; 45162306a36Sopenharmony_ci voltdm->write(clksetup, OMAP3_PRM_CLKSETUP_OFFSET); 45262306a36Sopenharmony_ci voltdm->write(voltoffset, OMAP3_PRM_VOLTOFFSET_OFFSET); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic void __init omap3_vc_init_channel(struct voltagedomain *voltdm) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci omap3_vc_init_pmic_signaling(voltdm); 45862306a36Sopenharmony_ci omap3_set_off_timings(voltdm); 45962306a36Sopenharmony_ci omap3_set_i2c_timings(voltdm); 46062306a36Sopenharmony_ci} 46162306a36Sopenharmony_ci 46262306a36Sopenharmony_ci/** 46362306a36Sopenharmony_ci * omap4_calc_volt_ramp - calculates voltage ramping delays on omap4 46462306a36Sopenharmony_ci * @voltdm: channel to calculate values for 46562306a36Sopenharmony_ci * @voltage_diff: voltage difference in microvolts 46662306a36Sopenharmony_ci * 46762306a36Sopenharmony_ci * Calculates voltage ramp prescaler + counter values for a voltage 46862306a36Sopenharmony_ci * difference on omap4. Returns a field value suitable for writing to 46962306a36Sopenharmony_ci * VOLTSETUP register for a channel in following format: 47062306a36Sopenharmony_ci * bits[8:9] prescaler ... bits[0:5] counter. See OMAP4 TRM for reference. 47162306a36Sopenharmony_ci */ 47262306a36Sopenharmony_cistatic u32 omap4_calc_volt_ramp(struct voltagedomain *voltdm, u32 voltage_diff) 47362306a36Sopenharmony_ci{ 47462306a36Sopenharmony_ci u32 prescaler; 47562306a36Sopenharmony_ci u32 cycles; 47662306a36Sopenharmony_ci u32 time; 47762306a36Sopenharmony_ci 47862306a36Sopenharmony_ci time = voltage_diff / voltdm->pmic->slew_rate; 47962306a36Sopenharmony_ci 48062306a36Sopenharmony_ci cycles = voltdm->sys_clk.rate / 1000 * time / 1000; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci cycles /= 64; 48362306a36Sopenharmony_ci prescaler = 0; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci /* shift to next prescaler until no overflow */ 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* scale for div 256 = 64 * 4 */ 48862306a36Sopenharmony_ci if (cycles > 63) { 48962306a36Sopenharmony_ci cycles /= 4; 49062306a36Sopenharmony_ci prescaler++; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci 49362306a36Sopenharmony_ci /* scale for div 512 = 256 * 2 */ 49462306a36Sopenharmony_ci if (cycles > 63) { 49562306a36Sopenharmony_ci cycles /= 2; 49662306a36Sopenharmony_ci prescaler++; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci /* scale for div 2048 = 512 * 4 */ 50062306a36Sopenharmony_ci if (cycles > 63) { 50162306a36Sopenharmony_ci cycles /= 4; 50262306a36Sopenharmony_ci prescaler++; 50362306a36Sopenharmony_ci } 50462306a36Sopenharmony_ci 50562306a36Sopenharmony_ci /* check for overflow => invalid ramp time */ 50662306a36Sopenharmony_ci if (cycles > 63) { 50762306a36Sopenharmony_ci pr_warn("%s: invalid setuptime for vdd_%s\n", __func__, 50862306a36Sopenharmony_ci voltdm->name); 50962306a36Sopenharmony_ci return 0; 51062306a36Sopenharmony_ci } 51162306a36Sopenharmony_ci 51262306a36Sopenharmony_ci cycles++; 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci return (prescaler << OMAP4430_RAMP_UP_PRESCAL_SHIFT) | 51562306a36Sopenharmony_ci (cycles << OMAP4430_RAMP_UP_COUNT_SHIFT); 51662306a36Sopenharmony_ci} 51762306a36Sopenharmony_ci 51862306a36Sopenharmony_ci/** 51962306a36Sopenharmony_ci * omap4_usec_to_val_scrm - convert microsecond value to SCRM module bitfield 52062306a36Sopenharmony_ci * @usec: microseconds 52162306a36Sopenharmony_ci * @shift: number of bits to shift left 52262306a36Sopenharmony_ci * @mask: bitfield mask 52362306a36Sopenharmony_ci * 52462306a36Sopenharmony_ci * Converts microsecond value to OMAP4 SCRM bitfield. Bitfield is 52562306a36Sopenharmony_ci * shifted to requested position, and checked agains the mask value. 52662306a36Sopenharmony_ci * If larger, forced to the max value of the field (i.e. the mask itself.) 52762306a36Sopenharmony_ci * Returns the SCRM bitfield value. 52862306a36Sopenharmony_ci */ 52962306a36Sopenharmony_cistatic u32 omap4_usec_to_val_scrm(u32 usec, int shift, u32 mask) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci u32 val; 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci val = omap_usec_to_32k(usec) << shift; 53462306a36Sopenharmony_ci 53562306a36Sopenharmony_ci /* Check for overflow, if yes, force to max value */ 53662306a36Sopenharmony_ci if (val > mask) 53762306a36Sopenharmony_ci val = mask; 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci return val; 54062306a36Sopenharmony_ci} 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci/** 54362306a36Sopenharmony_ci * omap4_set_timings - set voltage ramp timings for a channel 54462306a36Sopenharmony_ci * @voltdm: channel to configure 54562306a36Sopenharmony_ci * @off_mode: whether off-mode values are used 54662306a36Sopenharmony_ci * 54762306a36Sopenharmony_ci * Calculates and sets the voltage ramp up / down values for a channel. 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_cistatic void omap4_set_timings(struct voltagedomain *voltdm, bool off_mode) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci u32 val; 55262306a36Sopenharmony_ci u32 ramp; 55362306a36Sopenharmony_ci int offset; 55462306a36Sopenharmony_ci u32 tstart, tshut; 55562306a36Sopenharmony_ci 55662306a36Sopenharmony_ci if (off_mode) { 55762306a36Sopenharmony_ci ramp = omap4_calc_volt_ramp(voltdm, 55862306a36Sopenharmony_ci voltdm->vc_param->on - voltdm->vc_param->off); 55962306a36Sopenharmony_ci offset = voltdm->vfsm->voltsetup_off_reg; 56062306a36Sopenharmony_ci } else { 56162306a36Sopenharmony_ci ramp = omap4_calc_volt_ramp(voltdm, 56262306a36Sopenharmony_ci voltdm->vc_param->on - voltdm->vc_param->ret); 56362306a36Sopenharmony_ci offset = voltdm->vfsm->voltsetup_reg; 56462306a36Sopenharmony_ci } 56562306a36Sopenharmony_ci 56662306a36Sopenharmony_ci if (!ramp) 56762306a36Sopenharmony_ci return; 56862306a36Sopenharmony_ci 56962306a36Sopenharmony_ci val = voltdm->read(offset); 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci val |= ramp << OMAP4430_RAMP_DOWN_COUNT_SHIFT; 57262306a36Sopenharmony_ci 57362306a36Sopenharmony_ci val |= ramp << OMAP4430_RAMP_UP_COUNT_SHIFT; 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci voltdm->write(val, offset); 57662306a36Sopenharmony_ci 57762306a36Sopenharmony_ci omap_pm_get_oscillator(&tstart, &tshut); 57862306a36Sopenharmony_ci 57962306a36Sopenharmony_ci val = omap4_usec_to_val_scrm(tstart, OMAP4_SETUPTIME_SHIFT, 58062306a36Sopenharmony_ci OMAP4_SETUPTIME_MASK); 58162306a36Sopenharmony_ci val |= omap4_usec_to_val_scrm(tshut, OMAP4_DOWNTIME_SHIFT, 58262306a36Sopenharmony_ci OMAP4_DOWNTIME_MASK); 58362306a36Sopenharmony_ci 58462306a36Sopenharmony_ci writel_relaxed(val, OMAP4_SCRM_CLKSETUPTIME); 58562306a36Sopenharmony_ci} 58662306a36Sopenharmony_ci 58762306a36Sopenharmony_cistatic void __init omap4_vc_init_pmic_signaling(struct voltagedomain *voltdm) 58862306a36Sopenharmony_ci{ 58962306a36Sopenharmony_ci if (vc.vd) 59062306a36Sopenharmony_ci return; 59162306a36Sopenharmony_ci 59262306a36Sopenharmony_ci vc.vd = voltdm; 59362306a36Sopenharmony_ci voltdm->write(OMAP4_VDD_DEFAULT_VAL, OMAP4_PRM_VOLTCTRL_OFFSET); 59462306a36Sopenharmony_ci} 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci/* OMAP4 specific voltage init functions */ 59762306a36Sopenharmony_cistatic void __init omap4_vc_init_channel(struct voltagedomain *voltdm) 59862306a36Sopenharmony_ci{ 59962306a36Sopenharmony_ci omap4_vc_init_pmic_signaling(voltdm); 60062306a36Sopenharmony_ci omap4_set_timings(voltdm, true); 60162306a36Sopenharmony_ci omap4_set_timings(voltdm, false); 60262306a36Sopenharmony_ci} 60362306a36Sopenharmony_ci 60462306a36Sopenharmony_cistruct i2c_init_data { 60562306a36Sopenharmony_ci u8 loadbits; 60662306a36Sopenharmony_ci u8 load; 60762306a36Sopenharmony_ci u8 hsscll_38_4; 60862306a36Sopenharmony_ci u8 hsscll_26; 60962306a36Sopenharmony_ci u8 hsscll_19_2; 61062306a36Sopenharmony_ci u8 hsscll_16_8; 61162306a36Sopenharmony_ci u8 hsscll_12; 61262306a36Sopenharmony_ci}; 61362306a36Sopenharmony_ci 61462306a36Sopenharmony_cistatic const struct i2c_init_data omap4_i2c_timing_data[] __initconst = { 61562306a36Sopenharmony_ci { 61662306a36Sopenharmony_ci .load = 50, 61762306a36Sopenharmony_ci .loadbits = 0x3, 61862306a36Sopenharmony_ci .hsscll_38_4 = 13, 61962306a36Sopenharmony_ci .hsscll_26 = 11, 62062306a36Sopenharmony_ci .hsscll_19_2 = 9, 62162306a36Sopenharmony_ci .hsscll_16_8 = 9, 62262306a36Sopenharmony_ci .hsscll_12 = 8, 62362306a36Sopenharmony_ci }, 62462306a36Sopenharmony_ci { 62562306a36Sopenharmony_ci .load = 25, 62662306a36Sopenharmony_ci .loadbits = 0x2, 62762306a36Sopenharmony_ci .hsscll_38_4 = 13, 62862306a36Sopenharmony_ci .hsscll_26 = 11, 62962306a36Sopenharmony_ci .hsscll_19_2 = 9, 63062306a36Sopenharmony_ci .hsscll_16_8 = 9, 63162306a36Sopenharmony_ci .hsscll_12 = 8, 63262306a36Sopenharmony_ci }, 63362306a36Sopenharmony_ci { 63462306a36Sopenharmony_ci .load = 12, 63562306a36Sopenharmony_ci .loadbits = 0x1, 63662306a36Sopenharmony_ci .hsscll_38_4 = 11, 63762306a36Sopenharmony_ci .hsscll_26 = 10, 63862306a36Sopenharmony_ci .hsscll_19_2 = 9, 63962306a36Sopenharmony_ci .hsscll_16_8 = 9, 64062306a36Sopenharmony_ci .hsscll_12 = 8, 64162306a36Sopenharmony_ci }, 64262306a36Sopenharmony_ci { 64362306a36Sopenharmony_ci .load = 0, 64462306a36Sopenharmony_ci .loadbits = 0x0, 64562306a36Sopenharmony_ci .hsscll_38_4 = 12, 64662306a36Sopenharmony_ci .hsscll_26 = 10, 64762306a36Sopenharmony_ci .hsscll_19_2 = 9, 64862306a36Sopenharmony_ci .hsscll_16_8 = 8, 64962306a36Sopenharmony_ci .hsscll_12 = 8, 65062306a36Sopenharmony_ci }, 65162306a36Sopenharmony_ci}; 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_ci/** 65462306a36Sopenharmony_ci * omap4_vc_i2c_timing_init - sets up board I2C timing parameters 65562306a36Sopenharmony_ci * @voltdm: voltagedomain pointer to get data from 65662306a36Sopenharmony_ci * 65762306a36Sopenharmony_ci * Use PMIC + board supplied settings for calculating the total I2C 65862306a36Sopenharmony_ci * channel capacitance and set the timing parameters based on this. 65962306a36Sopenharmony_ci * Pre-calculated values are provided in data tables, as it is not 66062306a36Sopenharmony_ci * too straightforward to calculate these runtime. 66162306a36Sopenharmony_ci */ 66262306a36Sopenharmony_cistatic void __init omap4_vc_i2c_timing_init(struct voltagedomain *voltdm) 66362306a36Sopenharmony_ci{ 66462306a36Sopenharmony_ci u32 capacitance; 66562306a36Sopenharmony_ci u32 val; 66662306a36Sopenharmony_ci u16 hsscll; 66762306a36Sopenharmony_ci const struct i2c_init_data *i2c_data; 66862306a36Sopenharmony_ci 66962306a36Sopenharmony_ci if (!voltdm->pmic->i2c_high_speed) { 67062306a36Sopenharmony_ci pr_info("%s: using bootloader low-speed timings\n", __func__); 67162306a36Sopenharmony_ci return; 67262306a36Sopenharmony_ci } 67362306a36Sopenharmony_ci 67462306a36Sopenharmony_ci /* PCB trace capacitance, 0.125pF / mm => mm / 8 */ 67562306a36Sopenharmony_ci capacitance = DIV_ROUND_UP(sr_i2c_pcb_length, 8); 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* OMAP pad capacitance */ 67862306a36Sopenharmony_ci capacitance += 4; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci /* PMIC pad capacitance */ 68162306a36Sopenharmony_ci capacitance += voltdm->pmic->i2c_pad_load; 68262306a36Sopenharmony_ci 68362306a36Sopenharmony_ci /* Search for capacitance match in the table */ 68462306a36Sopenharmony_ci i2c_data = omap4_i2c_timing_data; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci while (i2c_data->load > capacitance) 68762306a36Sopenharmony_ci i2c_data++; 68862306a36Sopenharmony_ci 68962306a36Sopenharmony_ci /* Select proper values based on sysclk frequency */ 69062306a36Sopenharmony_ci switch (voltdm->sys_clk.rate) { 69162306a36Sopenharmony_ci case 38400000: 69262306a36Sopenharmony_ci hsscll = i2c_data->hsscll_38_4; 69362306a36Sopenharmony_ci break; 69462306a36Sopenharmony_ci case 26000000: 69562306a36Sopenharmony_ci hsscll = i2c_data->hsscll_26; 69662306a36Sopenharmony_ci break; 69762306a36Sopenharmony_ci case 19200000: 69862306a36Sopenharmony_ci hsscll = i2c_data->hsscll_19_2; 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci case 16800000: 70162306a36Sopenharmony_ci hsscll = i2c_data->hsscll_16_8; 70262306a36Sopenharmony_ci break; 70362306a36Sopenharmony_ci case 12000000: 70462306a36Sopenharmony_ci hsscll = i2c_data->hsscll_12; 70562306a36Sopenharmony_ci break; 70662306a36Sopenharmony_ci default: 70762306a36Sopenharmony_ci pr_warn("%s: unsupported sysclk rate: %d!\n", __func__, 70862306a36Sopenharmony_ci voltdm->sys_clk.rate); 70962306a36Sopenharmony_ci return; 71062306a36Sopenharmony_ci } 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci /* Loadbits define pull setup for the I2C channels */ 71362306a36Sopenharmony_ci val = i2c_data->loadbits << 25 | i2c_data->loadbits << 29; 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci /* Write to SYSCTRL_PADCONF_WKUP_CTRL_I2C_2 to setup I2C pull */ 71662306a36Sopenharmony_ci writel_relaxed(val, OMAP2_L4_IO_ADDRESS(OMAP4_CTRL_MODULE_PAD_WKUP + 71762306a36Sopenharmony_ci OMAP4_CTRL_MODULE_PAD_WKUP_CONTROL_I2C_2)); 71862306a36Sopenharmony_ci 71962306a36Sopenharmony_ci /* HSSCLH can always be zero */ 72062306a36Sopenharmony_ci val = hsscll << OMAP4430_HSSCLL_SHIFT; 72162306a36Sopenharmony_ci val |= (0x28 << OMAP4430_SCLL_SHIFT | 0x2c << OMAP4430_SCLH_SHIFT); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci /* Write setup times to I2C config register */ 72462306a36Sopenharmony_ci voltdm->write(val, OMAP4_PRM_VC_CFG_I2C_CLK_OFFSET); 72562306a36Sopenharmony_ci} 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci/** 73062306a36Sopenharmony_ci * omap_vc_i2c_init - initialize I2C interface to PMIC 73162306a36Sopenharmony_ci * @voltdm: voltage domain containing VC data 73262306a36Sopenharmony_ci * 73362306a36Sopenharmony_ci * Use PMIC supplied settings for I2C high-speed mode and 73462306a36Sopenharmony_ci * master code (if set) and program the VC I2C configuration 73562306a36Sopenharmony_ci * register. 73662306a36Sopenharmony_ci * 73762306a36Sopenharmony_ci * The VC I2C configuration is common to all VC channels, 73862306a36Sopenharmony_ci * so this function only configures I2C for the first VC 73962306a36Sopenharmony_ci * channel registers. All other VC channels will use the 74062306a36Sopenharmony_ci * same configuration. 74162306a36Sopenharmony_ci */ 74262306a36Sopenharmony_cistatic void __init omap_vc_i2c_init(struct voltagedomain *voltdm) 74362306a36Sopenharmony_ci{ 74462306a36Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 74562306a36Sopenharmony_ci static bool initialized; 74662306a36Sopenharmony_ci static bool i2c_high_speed; 74762306a36Sopenharmony_ci u8 mcode; 74862306a36Sopenharmony_ci 74962306a36Sopenharmony_ci if (initialized) { 75062306a36Sopenharmony_ci if (voltdm->pmic->i2c_high_speed != i2c_high_speed) 75162306a36Sopenharmony_ci pr_warn("%s: I2C config for vdd_%s does not match other channels (%u).\n", 75262306a36Sopenharmony_ci __func__, voltdm->name, i2c_high_speed); 75362306a36Sopenharmony_ci return; 75462306a36Sopenharmony_ci } 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci /* 75762306a36Sopenharmony_ci * Note that for omap3 OMAP3430_SREN_MASK clears SREN to work around 75862306a36Sopenharmony_ci * erratum i531 "Extra Power Consumed When Repeated Start Operation 75962306a36Sopenharmony_ci * Mode Is Enabled on I2C Interface Dedicated for Smart Reflex (I2C4)". 76062306a36Sopenharmony_ci * Otherwise I2C4 eventually leads into about 23mW extra power being 76162306a36Sopenharmony_ci * consumed even during off idle using VMODE. 76262306a36Sopenharmony_ci */ 76362306a36Sopenharmony_ci i2c_high_speed = voltdm->pmic->i2c_high_speed; 76462306a36Sopenharmony_ci if (i2c_high_speed) 76562306a36Sopenharmony_ci voltdm->rmw(vc->common->i2c_cfg_clear_mask, 76662306a36Sopenharmony_ci vc->common->i2c_cfg_hsen_mask, 76762306a36Sopenharmony_ci vc->common->i2c_cfg_reg); 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci mcode = voltdm->pmic->i2c_mcode; 77062306a36Sopenharmony_ci if (mcode) 77162306a36Sopenharmony_ci voltdm->rmw(vc->common->i2c_mcode_mask, 77262306a36Sopenharmony_ci mcode << __ffs(vc->common->i2c_mcode_mask), 77362306a36Sopenharmony_ci vc->common->i2c_cfg_reg); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci if (cpu_is_omap44xx()) 77662306a36Sopenharmony_ci omap4_vc_i2c_timing_init(voltdm); 77762306a36Sopenharmony_ci 77862306a36Sopenharmony_ci initialized = true; 77962306a36Sopenharmony_ci} 78062306a36Sopenharmony_ci 78162306a36Sopenharmony_ci/** 78262306a36Sopenharmony_ci * omap_vc_calc_vsel - calculate vsel value for a channel 78362306a36Sopenharmony_ci * @voltdm: channel to calculate value for 78462306a36Sopenharmony_ci * @uvolt: microvolt value to convert to vsel 78562306a36Sopenharmony_ci * 78662306a36Sopenharmony_ci * Converts a microvolt value to vsel value for the used PMIC. 78762306a36Sopenharmony_ci * This checks whether the microvolt value is out of bounds, and 78862306a36Sopenharmony_ci * adjusts the value accordingly. If unsupported value detected, 78962306a36Sopenharmony_ci * warning is thrown. 79062306a36Sopenharmony_ci */ 79162306a36Sopenharmony_cistatic u8 omap_vc_calc_vsel(struct voltagedomain *voltdm, u32 uvolt) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci if (voltdm->pmic->vddmin > uvolt) 79462306a36Sopenharmony_ci uvolt = voltdm->pmic->vddmin; 79562306a36Sopenharmony_ci if (voltdm->pmic->vddmax < uvolt) { 79662306a36Sopenharmony_ci WARN(1, "%s: voltage not supported by pmic: %u vs max %u\n", 79762306a36Sopenharmony_ci __func__, uvolt, voltdm->pmic->vddmax); 79862306a36Sopenharmony_ci /* Lets try maximum value anyway */ 79962306a36Sopenharmony_ci uvolt = voltdm->pmic->vddmax; 80062306a36Sopenharmony_ci } 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_ci return voltdm->pmic->uv_to_vsel(uvolt); 80362306a36Sopenharmony_ci} 80462306a36Sopenharmony_ci 80562306a36Sopenharmony_civoid __init omap_vc_init_channel(struct voltagedomain *voltdm) 80662306a36Sopenharmony_ci{ 80762306a36Sopenharmony_ci struct omap_vc_channel *vc = voltdm->vc; 80862306a36Sopenharmony_ci u8 on_vsel, onlp_vsel, ret_vsel, off_vsel; 80962306a36Sopenharmony_ci u32 val; 81062306a36Sopenharmony_ci 81162306a36Sopenharmony_ci if (!voltdm->pmic || !voltdm->pmic->uv_to_vsel) { 81262306a36Sopenharmony_ci pr_err("%s: No PMIC info for vdd_%s\n", __func__, voltdm->name); 81362306a36Sopenharmony_ci return; 81462306a36Sopenharmony_ci } 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci if (!voltdm->read || !voltdm->write) { 81762306a36Sopenharmony_ci pr_err("%s: No read/write API for accessing vdd_%s regs\n", 81862306a36Sopenharmony_ci __func__, voltdm->name); 81962306a36Sopenharmony_ci return; 82062306a36Sopenharmony_ci } 82162306a36Sopenharmony_ci 82262306a36Sopenharmony_ci vc->cfg_channel = 0; 82362306a36Sopenharmony_ci if (vc->flags & OMAP_VC_CHANNEL_CFG_MUTANT) 82462306a36Sopenharmony_ci vc_cfg_bits = &vc_mutant_channel_cfg; 82562306a36Sopenharmony_ci else 82662306a36Sopenharmony_ci vc_cfg_bits = &vc_default_channel_cfg; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci /* get PMIC/board specific settings */ 82962306a36Sopenharmony_ci vc->i2c_slave_addr = voltdm->pmic->i2c_slave_addr; 83062306a36Sopenharmony_ci vc->volt_reg_addr = voltdm->pmic->volt_reg_addr; 83162306a36Sopenharmony_ci vc->cmd_reg_addr = voltdm->pmic->cmd_reg_addr; 83262306a36Sopenharmony_ci 83362306a36Sopenharmony_ci /* Configure the i2c slave address for this VC */ 83462306a36Sopenharmony_ci voltdm->rmw(vc->smps_sa_mask, 83562306a36Sopenharmony_ci vc->i2c_slave_addr << __ffs(vc->smps_sa_mask), 83662306a36Sopenharmony_ci vc->smps_sa_reg); 83762306a36Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->sa; 83862306a36Sopenharmony_ci 83962306a36Sopenharmony_ci /* 84062306a36Sopenharmony_ci * Configure the PMIC register addresses. 84162306a36Sopenharmony_ci */ 84262306a36Sopenharmony_ci voltdm->rmw(vc->smps_volra_mask, 84362306a36Sopenharmony_ci vc->volt_reg_addr << __ffs(vc->smps_volra_mask), 84462306a36Sopenharmony_ci vc->smps_volra_reg); 84562306a36Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->rav; 84662306a36Sopenharmony_ci 84762306a36Sopenharmony_ci if (vc->cmd_reg_addr) { 84862306a36Sopenharmony_ci voltdm->rmw(vc->smps_cmdra_mask, 84962306a36Sopenharmony_ci vc->cmd_reg_addr << __ffs(vc->smps_cmdra_mask), 85062306a36Sopenharmony_ci vc->smps_cmdra_reg); 85162306a36Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->rac; 85262306a36Sopenharmony_ci } 85362306a36Sopenharmony_ci 85462306a36Sopenharmony_ci if (vc->cmd_reg_addr == vc->volt_reg_addr) 85562306a36Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->racen; 85662306a36Sopenharmony_ci 85762306a36Sopenharmony_ci /* Set up the on, inactive, retention and off voltage */ 85862306a36Sopenharmony_ci on_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->on); 85962306a36Sopenharmony_ci onlp_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->onlp); 86062306a36Sopenharmony_ci ret_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->ret); 86162306a36Sopenharmony_ci off_vsel = omap_vc_calc_vsel(voltdm, voltdm->vc_param->off); 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_ci val = ((on_vsel << vc->common->cmd_on_shift) | 86462306a36Sopenharmony_ci (onlp_vsel << vc->common->cmd_onlp_shift) | 86562306a36Sopenharmony_ci (ret_vsel << vc->common->cmd_ret_shift) | 86662306a36Sopenharmony_ci (off_vsel << vc->common->cmd_off_shift)); 86762306a36Sopenharmony_ci voltdm->write(val, vc->cmdval_reg); 86862306a36Sopenharmony_ci vc->cfg_channel |= vc_cfg_bits->cmd; 86962306a36Sopenharmony_ci 87062306a36Sopenharmony_ci /* Channel configuration */ 87162306a36Sopenharmony_ci omap_vc_config_channel(voltdm); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci omap_vc_i2c_init(voltdm); 87462306a36Sopenharmony_ci 87562306a36Sopenharmony_ci if (cpu_is_omap34xx()) 87662306a36Sopenharmony_ci omap3_vc_init_channel(voltdm); 87762306a36Sopenharmony_ci else if (cpu_is_omap44xx()) 87862306a36Sopenharmony_ci omap4_vc_init_channel(voltdm); 87962306a36Sopenharmony_ci} 880