18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/**
38c2ecf20Sopenharmony_ci * OMAP and TWL PMIC specific initializations.
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2010 Texas Instruments Incorporated.
68c2ecf20Sopenharmony_ci * Thara Gopinath
78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Texas Instruments Incorporated.
88c2ecf20Sopenharmony_ci * Nishanth Menon
98c2ecf20Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation
108c2ecf20Sopenharmony_ci * Paul Walmsley
118c2ecf20Sopenharmony_ci */
128c2ecf20Sopenharmony_ci
138c2ecf20Sopenharmony_ci#include <linux/err.h>
148c2ecf20Sopenharmony_ci#include <linux/io.h>
158c2ecf20Sopenharmony_ci#include <linux/kernel.h>
168c2ecf20Sopenharmony_ci#include <linux/mfd/twl.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_ci#include "soc.h"
198c2ecf20Sopenharmony_ci#include "voltage.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#include "pm.h"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_ci#define OMAP3_SRI2C_SLAVE_ADDR		0x12
248c2ecf20Sopenharmony_ci#define OMAP3_VDD_MPU_SR_CONTROL_REG	0x00
258c2ecf20Sopenharmony_ci#define OMAP3_VDD_CORE_SR_CONTROL_REG	0x01
268c2ecf20Sopenharmony_ci#define OMAP3_VP_CONFIG_ERROROFFSET	0x00
278c2ecf20Sopenharmony_ci#define OMAP3_VP_VSTEPMIN_VSTEPMIN	0x1
288c2ecf20Sopenharmony_ci#define OMAP3_VP_VSTEPMAX_VSTEPMAX	0x04
298c2ecf20Sopenharmony_ci#define OMAP3_VP_VLIMITTO_TIMEOUT_US	200
308c2ecf20Sopenharmony_ci
318c2ecf20Sopenharmony_ci#define OMAP4_SRI2C_SLAVE_ADDR		0x12
328c2ecf20Sopenharmony_ci#define OMAP4_VDD_MPU_SR_VOLT_REG	0x55
338c2ecf20Sopenharmony_ci#define OMAP4_VDD_MPU_SR_CMD_REG	0x56
348c2ecf20Sopenharmony_ci#define OMAP4_VDD_IVA_SR_VOLT_REG	0x5B
358c2ecf20Sopenharmony_ci#define OMAP4_VDD_IVA_SR_CMD_REG	0x5C
368c2ecf20Sopenharmony_ci#define OMAP4_VDD_CORE_SR_VOLT_REG	0x61
378c2ecf20Sopenharmony_ci#define OMAP4_VDD_CORE_SR_CMD_REG	0x62
388c2ecf20Sopenharmony_ci
398c2ecf20Sopenharmony_cistatic bool is_offset_valid;
408c2ecf20Sopenharmony_cistatic u8 smps_offset;
418c2ecf20Sopenharmony_ci
428c2ecf20Sopenharmony_ci#define REG_SMPS_OFFSET         0xE0
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic unsigned long twl4030_vsel_to_uv(const u8 vsel)
458c2ecf20Sopenharmony_ci{
468c2ecf20Sopenharmony_ci	return (((vsel * 125) + 6000)) * 100;
478c2ecf20Sopenharmony_ci}
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_cistatic u8 twl4030_uv_to_vsel(unsigned long uv)
508c2ecf20Sopenharmony_ci{
518c2ecf20Sopenharmony_ci	return DIV_ROUND_UP(uv - 600000, 12500);
528c2ecf20Sopenharmony_ci}
538c2ecf20Sopenharmony_ci
548c2ecf20Sopenharmony_cistatic unsigned long twl6030_vsel_to_uv(const u8 vsel)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	/*
578c2ecf20Sopenharmony_ci	 * In TWL6030 depending on the value of SMPS_OFFSET
588c2ecf20Sopenharmony_ci	 * efuse register the voltage range supported in
598c2ecf20Sopenharmony_ci	 * standard mode can be either between 0.6V - 1.3V or
608c2ecf20Sopenharmony_ci	 * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse
618c2ecf20Sopenharmony_ci	 * is programmed to all 0's where as starting from
628c2ecf20Sopenharmony_ci	 * TWL6030 ES1.1 the efuse is programmed to 1
638c2ecf20Sopenharmony_ci	 */
648c2ecf20Sopenharmony_ci	if (!is_offset_valid) {
658c2ecf20Sopenharmony_ci		twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset,
668c2ecf20Sopenharmony_ci				REG_SMPS_OFFSET);
678c2ecf20Sopenharmony_ci		is_offset_valid = true;
688c2ecf20Sopenharmony_ci	}
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci	if (!vsel)
718c2ecf20Sopenharmony_ci		return 0;
728c2ecf20Sopenharmony_ci	/*
738c2ecf20Sopenharmony_ci	 * There is no specific formula for voltage to vsel
748c2ecf20Sopenharmony_ci	 * conversion above 1.3V. There are special hardcoded
758c2ecf20Sopenharmony_ci	 * values for voltages above 1.3V. Currently we are
768c2ecf20Sopenharmony_ci	 * hardcoding only for 1.35 V which is used for 1GH OPP for
778c2ecf20Sopenharmony_ci	 * OMAP4430.
788c2ecf20Sopenharmony_ci	 */
798c2ecf20Sopenharmony_ci	if (vsel == 0x3A)
808c2ecf20Sopenharmony_ci		return 1350000;
818c2ecf20Sopenharmony_ci
828c2ecf20Sopenharmony_ci	if (smps_offset & 0x8)
838c2ecf20Sopenharmony_ci		return ((((vsel - 1) * 1266) + 70900)) * 10;
848c2ecf20Sopenharmony_ci	else
858c2ecf20Sopenharmony_ci		return ((((vsel - 1) * 1266) + 60770)) * 10;
868c2ecf20Sopenharmony_ci}
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_cistatic u8 twl6030_uv_to_vsel(unsigned long uv)
898c2ecf20Sopenharmony_ci{
908c2ecf20Sopenharmony_ci	/*
918c2ecf20Sopenharmony_ci	 * In TWL6030 depending on the value of SMPS_OFFSET
928c2ecf20Sopenharmony_ci	 * efuse register the voltage range supported in
938c2ecf20Sopenharmony_ci	 * standard mode can be either between 0.6V - 1.3V or
948c2ecf20Sopenharmony_ci	 * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse
958c2ecf20Sopenharmony_ci	 * is programmed to all 0's where as starting from
968c2ecf20Sopenharmony_ci	 * TWL6030 ES1.1 the efuse is programmed to 1
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	if (!is_offset_valid) {
998c2ecf20Sopenharmony_ci		twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset,
1008c2ecf20Sopenharmony_ci				REG_SMPS_OFFSET);
1018c2ecf20Sopenharmony_ci		is_offset_valid = true;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci	if (!uv)
1058c2ecf20Sopenharmony_ci		return 0x00;
1068c2ecf20Sopenharmony_ci	/*
1078c2ecf20Sopenharmony_ci	 * There is no specific formula for voltage to vsel
1088c2ecf20Sopenharmony_ci	 * conversion above 1.3V. There are special hardcoded
1098c2ecf20Sopenharmony_ci	 * values for voltages above 1.3V. Currently we are
1108c2ecf20Sopenharmony_ci	 * hardcoding only for 1.35 V which is used for 1GH OPP for
1118c2ecf20Sopenharmony_ci	 * OMAP4430.
1128c2ecf20Sopenharmony_ci	 */
1138c2ecf20Sopenharmony_ci	if (uv > twl6030_vsel_to_uv(0x39)) {
1148c2ecf20Sopenharmony_ci		if (uv == 1350000)
1158c2ecf20Sopenharmony_ci			return 0x3A;
1168c2ecf20Sopenharmony_ci		pr_err("%s:OUT OF RANGE! non mapped vsel for %ld Vs max %ld\n",
1178c2ecf20Sopenharmony_ci			__func__, uv, twl6030_vsel_to_uv(0x39));
1188c2ecf20Sopenharmony_ci		return 0x3A;
1198c2ecf20Sopenharmony_ci	}
1208c2ecf20Sopenharmony_ci
1218c2ecf20Sopenharmony_ci	if (smps_offset & 0x8)
1228c2ecf20Sopenharmony_ci		return DIV_ROUND_UP(uv - 709000, 12660) + 1;
1238c2ecf20Sopenharmony_ci	else
1248c2ecf20Sopenharmony_ci		return DIV_ROUND_UP(uv - 607700, 12660) + 1;
1258c2ecf20Sopenharmony_ci}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap3_mpu_pmic = {
1288c2ecf20Sopenharmony_ci	.slew_rate		= 4000,
1298c2ecf20Sopenharmony_ci	.step_size		= 12500,
1308c2ecf20Sopenharmony_ci	.vp_erroroffset		= OMAP3_VP_CONFIG_ERROROFFSET,
1318c2ecf20Sopenharmony_ci	.vp_vstepmin		= OMAP3_VP_VSTEPMIN_VSTEPMIN,
1328c2ecf20Sopenharmony_ci	.vp_vstepmax		= OMAP3_VP_VSTEPMAX_VSTEPMAX,
1338c2ecf20Sopenharmony_ci	.vddmin			= 600000,
1348c2ecf20Sopenharmony_ci	.vddmax			= 1450000,
1358c2ecf20Sopenharmony_ci	.vp_timeout_us		= OMAP3_VP_VLIMITTO_TIMEOUT_US,
1368c2ecf20Sopenharmony_ci	.i2c_slave_addr		= OMAP3_SRI2C_SLAVE_ADDR,
1378c2ecf20Sopenharmony_ci	.volt_reg_addr		= OMAP3_VDD_MPU_SR_CONTROL_REG,
1388c2ecf20Sopenharmony_ci	.i2c_high_speed		= true,
1398c2ecf20Sopenharmony_ci	.vsel_to_uv		= twl4030_vsel_to_uv,
1408c2ecf20Sopenharmony_ci	.uv_to_vsel		= twl4030_uv_to_vsel,
1418c2ecf20Sopenharmony_ci};
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap3_core_pmic = {
1448c2ecf20Sopenharmony_ci	.slew_rate		= 4000,
1458c2ecf20Sopenharmony_ci	.step_size		= 12500,
1468c2ecf20Sopenharmony_ci	.vp_erroroffset		= OMAP3_VP_CONFIG_ERROROFFSET,
1478c2ecf20Sopenharmony_ci	.vp_vstepmin		= OMAP3_VP_VSTEPMIN_VSTEPMIN,
1488c2ecf20Sopenharmony_ci	.vp_vstepmax		= OMAP3_VP_VSTEPMAX_VSTEPMAX,
1498c2ecf20Sopenharmony_ci	.vddmin			= 600000,
1508c2ecf20Sopenharmony_ci	.vddmax			= 1450000,
1518c2ecf20Sopenharmony_ci	.vp_timeout_us		= OMAP3_VP_VLIMITTO_TIMEOUT_US,
1528c2ecf20Sopenharmony_ci	.i2c_slave_addr		= OMAP3_SRI2C_SLAVE_ADDR,
1538c2ecf20Sopenharmony_ci	.volt_reg_addr		= OMAP3_VDD_CORE_SR_CONTROL_REG,
1548c2ecf20Sopenharmony_ci	.i2c_high_speed		= true,
1558c2ecf20Sopenharmony_ci	.vsel_to_uv		= twl4030_vsel_to_uv,
1568c2ecf20Sopenharmony_ci	.uv_to_vsel		= twl4030_uv_to_vsel,
1578c2ecf20Sopenharmony_ci};
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap4_mpu_pmic = {
1608c2ecf20Sopenharmony_ci	.slew_rate		= 4000,
1618c2ecf20Sopenharmony_ci	.step_size		= 12660,
1628c2ecf20Sopenharmony_ci	.vp_erroroffset		= OMAP4_VP_CONFIG_ERROROFFSET,
1638c2ecf20Sopenharmony_ci	.vp_vstepmin		= OMAP4_VP_VSTEPMIN_VSTEPMIN,
1648c2ecf20Sopenharmony_ci	.vp_vstepmax		= OMAP4_VP_VSTEPMAX_VSTEPMAX,
1658c2ecf20Sopenharmony_ci	.vddmin			= 0,
1668c2ecf20Sopenharmony_ci	.vddmax			= 2100000,
1678c2ecf20Sopenharmony_ci	.vp_timeout_us		= OMAP4_VP_VLIMITTO_TIMEOUT_US,
1688c2ecf20Sopenharmony_ci	.i2c_slave_addr		= OMAP4_SRI2C_SLAVE_ADDR,
1698c2ecf20Sopenharmony_ci	.volt_reg_addr		= OMAP4_VDD_MPU_SR_VOLT_REG,
1708c2ecf20Sopenharmony_ci	.cmd_reg_addr		= OMAP4_VDD_MPU_SR_CMD_REG,
1718c2ecf20Sopenharmony_ci	.i2c_high_speed		= true,
1728c2ecf20Sopenharmony_ci	.i2c_pad_load		= 3,
1738c2ecf20Sopenharmony_ci	.vsel_to_uv		= twl6030_vsel_to_uv,
1748c2ecf20Sopenharmony_ci	.uv_to_vsel		= twl6030_uv_to_vsel,
1758c2ecf20Sopenharmony_ci};
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap4_iva_pmic = {
1788c2ecf20Sopenharmony_ci	.slew_rate		= 4000,
1798c2ecf20Sopenharmony_ci	.step_size		= 12660,
1808c2ecf20Sopenharmony_ci	.vp_erroroffset		= OMAP4_VP_CONFIG_ERROROFFSET,
1818c2ecf20Sopenharmony_ci	.vp_vstepmin		= OMAP4_VP_VSTEPMIN_VSTEPMIN,
1828c2ecf20Sopenharmony_ci	.vp_vstepmax		= OMAP4_VP_VSTEPMAX_VSTEPMAX,
1838c2ecf20Sopenharmony_ci	.vddmin			= 0,
1848c2ecf20Sopenharmony_ci	.vddmax			= 2100000,
1858c2ecf20Sopenharmony_ci	.vp_timeout_us		= OMAP4_VP_VLIMITTO_TIMEOUT_US,
1868c2ecf20Sopenharmony_ci	.i2c_slave_addr		= OMAP4_SRI2C_SLAVE_ADDR,
1878c2ecf20Sopenharmony_ci	.volt_reg_addr		= OMAP4_VDD_IVA_SR_VOLT_REG,
1888c2ecf20Sopenharmony_ci	.cmd_reg_addr		= OMAP4_VDD_IVA_SR_CMD_REG,
1898c2ecf20Sopenharmony_ci	.i2c_high_speed		= true,
1908c2ecf20Sopenharmony_ci	.i2c_pad_load		= 3,
1918c2ecf20Sopenharmony_ci	.vsel_to_uv		= twl6030_vsel_to_uv,
1928c2ecf20Sopenharmony_ci	.uv_to_vsel		= twl6030_uv_to_vsel,
1938c2ecf20Sopenharmony_ci};
1948c2ecf20Sopenharmony_ci
1958c2ecf20Sopenharmony_cistatic struct omap_voltdm_pmic omap4_core_pmic = {
1968c2ecf20Sopenharmony_ci	.slew_rate		= 4000,
1978c2ecf20Sopenharmony_ci	.step_size		= 12660,
1988c2ecf20Sopenharmony_ci	.vp_erroroffset		= OMAP4_VP_CONFIG_ERROROFFSET,
1998c2ecf20Sopenharmony_ci	.vp_vstepmin		= OMAP4_VP_VSTEPMIN_VSTEPMIN,
2008c2ecf20Sopenharmony_ci	.vp_vstepmax		= OMAP4_VP_VSTEPMAX_VSTEPMAX,
2018c2ecf20Sopenharmony_ci	.vddmin			= 0,
2028c2ecf20Sopenharmony_ci	.vddmax			= 2100000,
2038c2ecf20Sopenharmony_ci	.vp_timeout_us		= OMAP4_VP_VLIMITTO_TIMEOUT_US,
2048c2ecf20Sopenharmony_ci	.i2c_slave_addr		= OMAP4_SRI2C_SLAVE_ADDR,
2058c2ecf20Sopenharmony_ci	.volt_reg_addr		= OMAP4_VDD_CORE_SR_VOLT_REG,
2068c2ecf20Sopenharmony_ci	.cmd_reg_addr		= OMAP4_VDD_CORE_SR_CMD_REG,
2078c2ecf20Sopenharmony_ci	.i2c_high_speed		= true,
2088c2ecf20Sopenharmony_ci	.i2c_pad_load		= 3,
2098c2ecf20Sopenharmony_ci	.vsel_to_uv		= twl6030_vsel_to_uv,
2108c2ecf20Sopenharmony_ci	.uv_to_vsel		= twl6030_uv_to_vsel,
2118c2ecf20Sopenharmony_ci};
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ciint __init omap4_twl_init(void)
2148c2ecf20Sopenharmony_ci{
2158c2ecf20Sopenharmony_ci	struct voltagedomain *voltdm;
2168c2ecf20Sopenharmony_ci
2178c2ecf20Sopenharmony_ci	if (!cpu_is_omap44xx() ||
2188c2ecf20Sopenharmony_ci	    of_find_compatible_node(NULL, NULL, "motorola,cpcap"))
2198c2ecf20Sopenharmony_ci		return -ENODEV;
2208c2ecf20Sopenharmony_ci
2218c2ecf20Sopenharmony_ci	voltdm = voltdm_lookup("mpu");
2228c2ecf20Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap4_mpu_pmic);
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	voltdm = voltdm_lookup("iva");
2258c2ecf20Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap4_iva_pmic);
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	voltdm = voltdm_lookup("core");
2288c2ecf20Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap4_core_pmic);
2298c2ecf20Sopenharmony_ci
2308c2ecf20Sopenharmony_ci	return 0;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ciint __init omap3_twl_init(void)
2348c2ecf20Sopenharmony_ci{
2358c2ecf20Sopenharmony_ci	struct voltagedomain *voltdm;
2368c2ecf20Sopenharmony_ci
2378c2ecf20Sopenharmony_ci	if (!cpu_is_omap34xx())
2388c2ecf20Sopenharmony_ci		return -ENODEV;
2398c2ecf20Sopenharmony_ci
2408c2ecf20Sopenharmony_ci	voltdm = voltdm_lookup("mpu_iva");
2418c2ecf20Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic);
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	voltdm = voltdm_lookup("core");
2448c2ecf20Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap3_core_pmic);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	return 0;
2478c2ecf20Sopenharmony_ci}
248