162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * OMAP and TWL PMIC specific initializations.
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2010 Texas Instruments Incorporated.
662306a36Sopenharmony_ci * Thara Gopinath
762306a36Sopenharmony_ci * Copyright (C) 2009 Texas Instruments Incorporated.
862306a36Sopenharmony_ci * Nishanth Menon
962306a36Sopenharmony_ci * Copyright (C) 2009 Nokia Corporation
1062306a36Sopenharmony_ci * Paul Walmsley
1162306a36Sopenharmony_ci */
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include <linux/err.h>
1462306a36Sopenharmony_ci#include <linux/io.h>
1562306a36Sopenharmony_ci#include <linux/kernel.h>
1662306a36Sopenharmony_ci#include <linux/mfd/twl.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci#include "soc.h"
1962306a36Sopenharmony_ci#include "voltage.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci#include "pm.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci#define OMAP3_SRI2C_SLAVE_ADDR		0x12
2462306a36Sopenharmony_ci#define OMAP3_VDD_MPU_SR_CONTROL_REG	0x00
2562306a36Sopenharmony_ci#define OMAP3_VDD_CORE_SR_CONTROL_REG	0x01
2662306a36Sopenharmony_ci#define OMAP3_VP_CONFIG_ERROROFFSET	0x00
2762306a36Sopenharmony_ci#define OMAP3_VP_VSTEPMIN_VSTEPMIN	0x1
2862306a36Sopenharmony_ci#define OMAP3_VP_VSTEPMAX_VSTEPMAX	0x04
2962306a36Sopenharmony_ci#define OMAP3_VP_VLIMITTO_TIMEOUT_US	200
3062306a36Sopenharmony_ci
3162306a36Sopenharmony_ci#define OMAP4_SRI2C_SLAVE_ADDR		0x12
3262306a36Sopenharmony_ci#define OMAP4_VDD_MPU_SR_VOLT_REG	0x55
3362306a36Sopenharmony_ci#define OMAP4_VDD_MPU_SR_CMD_REG	0x56
3462306a36Sopenharmony_ci#define OMAP4_VDD_IVA_SR_VOLT_REG	0x5B
3562306a36Sopenharmony_ci#define OMAP4_VDD_IVA_SR_CMD_REG	0x5C
3662306a36Sopenharmony_ci#define OMAP4_VDD_CORE_SR_VOLT_REG	0x61
3762306a36Sopenharmony_ci#define OMAP4_VDD_CORE_SR_CMD_REG	0x62
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_cistatic bool is_offset_valid;
4062306a36Sopenharmony_cistatic u8 smps_offset;
4162306a36Sopenharmony_ci
4262306a36Sopenharmony_ci#define REG_SMPS_OFFSET         0xE0
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic unsigned long twl4030_vsel_to_uv(const u8 vsel)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	return (((vsel * 125) + 6000)) * 100;
4762306a36Sopenharmony_ci}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_cistatic u8 twl4030_uv_to_vsel(unsigned long uv)
5062306a36Sopenharmony_ci{
5162306a36Sopenharmony_ci	return DIV_ROUND_UP(uv - 600000, 12500);
5262306a36Sopenharmony_ci}
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic unsigned long twl6030_vsel_to_uv(const u8 vsel)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	/*
5762306a36Sopenharmony_ci	 * In TWL6030 depending on the value of SMPS_OFFSET
5862306a36Sopenharmony_ci	 * efuse register the voltage range supported in
5962306a36Sopenharmony_ci	 * standard mode can be either between 0.6V - 1.3V or
6062306a36Sopenharmony_ci	 * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse
6162306a36Sopenharmony_ci	 * is programmed to all 0's where as starting from
6262306a36Sopenharmony_ci	 * TWL6030 ES1.1 the efuse is programmed to 1
6362306a36Sopenharmony_ci	 */
6462306a36Sopenharmony_ci	if (!is_offset_valid) {
6562306a36Sopenharmony_ci		twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset,
6662306a36Sopenharmony_ci				REG_SMPS_OFFSET);
6762306a36Sopenharmony_ci		is_offset_valid = true;
6862306a36Sopenharmony_ci	}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	if (!vsel)
7162306a36Sopenharmony_ci		return 0;
7262306a36Sopenharmony_ci	/*
7362306a36Sopenharmony_ci	 * There is no specific formula for voltage to vsel
7462306a36Sopenharmony_ci	 * conversion above 1.3V. There are special hardcoded
7562306a36Sopenharmony_ci	 * values for voltages above 1.3V. Currently we are
7662306a36Sopenharmony_ci	 * hardcoding only for 1.35 V which is used for 1GH OPP for
7762306a36Sopenharmony_ci	 * OMAP4430.
7862306a36Sopenharmony_ci	 */
7962306a36Sopenharmony_ci	if (vsel == 0x3A)
8062306a36Sopenharmony_ci		return 1350000;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	if (smps_offset & 0x8)
8362306a36Sopenharmony_ci		return ((((vsel - 1) * 1266) + 70900)) * 10;
8462306a36Sopenharmony_ci	else
8562306a36Sopenharmony_ci		return ((((vsel - 1) * 1266) + 60770)) * 10;
8662306a36Sopenharmony_ci}
8762306a36Sopenharmony_ci
8862306a36Sopenharmony_cistatic u8 twl6030_uv_to_vsel(unsigned long uv)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	/*
9162306a36Sopenharmony_ci	 * In TWL6030 depending on the value of SMPS_OFFSET
9262306a36Sopenharmony_ci	 * efuse register the voltage range supported in
9362306a36Sopenharmony_ci	 * standard mode can be either between 0.6V - 1.3V or
9462306a36Sopenharmony_ci	 * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse
9562306a36Sopenharmony_ci	 * is programmed to all 0's where as starting from
9662306a36Sopenharmony_ci	 * TWL6030 ES1.1 the efuse is programmed to 1
9762306a36Sopenharmony_ci	 */
9862306a36Sopenharmony_ci	if (!is_offset_valid) {
9962306a36Sopenharmony_ci		twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset,
10062306a36Sopenharmony_ci				REG_SMPS_OFFSET);
10162306a36Sopenharmony_ci		is_offset_valid = true;
10262306a36Sopenharmony_ci	}
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	if (!uv)
10562306a36Sopenharmony_ci		return 0x00;
10662306a36Sopenharmony_ci	/*
10762306a36Sopenharmony_ci	 * There is no specific formula for voltage to vsel
10862306a36Sopenharmony_ci	 * conversion above 1.3V. There are special hardcoded
10962306a36Sopenharmony_ci	 * values for voltages above 1.3V. Currently we are
11062306a36Sopenharmony_ci	 * hardcoding only for 1.35 V which is used for 1GH OPP for
11162306a36Sopenharmony_ci	 * OMAP4430.
11262306a36Sopenharmony_ci	 */
11362306a36Sopenharmony_ci	if (uv > twl6030_vsel_to_uv(0x39)) {
11462306a36Sopenharmony_ci		if (uv == 1350000)
11562306a36Sopenharmony_ci			return 0x3A;
11662306a36Sopenharmony_ci		pr_err("%s:OUT OF RANGE! non mapped vsel for %ld Vs max %ld\n",
11762306a36Sopenharmony_ci			__func__, uv, twl6030_vsel_to_uv(0x39));
11862306a36Sopenharmony_ci		return 0x3A;
11962306a36Sopenharmony_ci	}
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	if (smps_offset & 0x8)
12262306a36Sopenharmony_ci		return DIV_ROUND_UP(uv - 709000, 12660) + 1;
12362306a36Sopenharmony_ci	else
12462306a36Sopenharmony_ci		return DIV_ROUND_UP(uv - 607700, 12660) + 1;
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap3_mpu_pmic = {
12862306a36Sopenharmony_ci	.slew_rate		= 4000,
12962306a36Sopenharmony_ci	.step_size		= 12500,
13062306a36Sopenharmony_ci	.vp_erroroffset		= OMAP3_VP_CONFIG_ERROROFFSET,
13162306a36Sopenharmony_ci	.vp_vstepmin		= OMAP3_VP_VSTEPMIN_VSTEPMIN,
13262306a36Sopenharmony_ci	.vp_vstepmax		= OMAP3_VP_VSTEPMAX_VSTEPMAX,
13362306a36Sopenharmony_ci	.vddmin			= 600000,
13462306a36Sopenharmony_ci	.vddmax			= 1450000,
13562306a36Sopenharmony_ci	.vp_timeout_us		= OMAP3_VP_VLIMITTO_TIMEOUT_US,
13662306a36Sopenharmony_ci	.i2c_slave_addr		= OMAP3_SRI2C_SLAVE_ADDR,
13762306a36Sopenharmony_ci	.volt_reg_addr		= OMAP3_VDD_MPU_SR_CONTROL_REG,
13862306a36Sopenharmony_ci	.i2c_high_speed		= true,
13962306a36Sopenharmony_ci	.vsel_to_uv		= twl4030_vsel_to_uv,
14062306a36Sopenharmony_ci	.uv_to_vsel		= twl4030_uv_to_vsel,
14162306a36Sopenharmony_ci};
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap3_core_pmic = {
14462306a36Sopenharmony_ci	.slew_rate		= 4000,
14562306a36Sopenharmony_ci	.step_size		= 12500,
14662306a36Sopenharmony_ci	.vp_erroroffset		= OMAP3_VP_CONFIG_ERROROFFSET,
14762306a36Sopenharmony_ci	.vp_vstepmin		= OMAP3_VP_VSTEPMIN_VSTEPMIN,
14862306a36Sopenharmony_ci	.vp_vstepmax		= OMAP3_VP_VSTEPMAX_VSTEPMAX,
14962306a36Sopenharmony_ci	.vddmin			= 600000,
15062306a36Sopenharmony_ci	.vddmax			= 1450000,
15162306a36Sopenharmony_ci	.vp_timeout_us		= OMAP3_VP_VLIMITTO_TIMEOUT_US,
15262306a36Sopenharmony_ci	.i2c_slave_addr		= OMAP3_SRI2C_SLAVE_ADDR,
15362306a36Sopenharmony_ci	.volt_reg_addr		= OMAP3_VDD_CORE_SR_CONTROL_REG,
15462306a36Sopenharmony_ci	.i2c_high_speed		= true,
15562306a36Sopenharmony_ci	.vsel_to_uv		= twl4030_vsel_to_uv,
15662306a36Sopenharmony_ci	.uv_to_vsel		= twl4030_uv_to_vsel,
15762306a36Sopenharmony_ci};
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap4_mpu_pmic = {
16062306a36Sopenharmony_ci	.slew_rate		= 4000,
16162306a36Sopenharmony_ci	.step_size		= 12660,
16262306a36Sopenharmony_ci	.vp_erroroffset		= OMAP4_VP_CONFIG_ERROROFFSET,
16362306a36Sopenharmony_ci	.vp_vstepmin		= OMAP4_VP_VSTEPMIN_VSTEPMIN,
16462306a36Sopenharmony_ci	.vp_vstepmax		= OMAP4_VP_VSTEPMAX_VSTEPMAX,
16562306a36Sopenharmony_ci	.vddmin			= 0,
16662306a36Sopenharmony_ci	.vddmax			= 2100000,
16762306a36Sopenharmony_ci	.vp_timeout_us		= OMAP4_VP_VLIMITTO_TIMEOUT_US,
16862306a36Sopenharmony_ci	.i2c_slave_addr		= OMAP4_SRI2C_SLAVE_ADDR,
16962306a36Sopenharmony_ci	.volt_reg_addr		= OMAP4_VDD_MPU_SR_VOLT_REG,
17062306a36Sopenharmony_ci	.cmd_reg_addr		= OMAP4_VDD_MPU_SR_CMD_REG,
17162306a36Sopenharmony_ci	.i2c_high_speed		= true,
17262306a36Sopenharmony_ci	.i2c_pad_load		= 3,
17362306a36Sopenharmony_ci	.vsel_to_uv		= twl6030_vsel_to_uv,
17462306a36Sopenharmony_ci	.uv_to_vsel		= twl6030_uv_to_vsel,
17562306a36Sopenharmony_ci};
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap4_iva_pmic = {
17862306a36Sopenharmony_ci	.slew_rate		= 4000,
17962306a36Sopenharmony_ci	.step_size		= 12660,
18062306a36Sopenharmony_ci	.vp_erroroffset		= OMAP4_VP_CONFIG_ERROROFFSET,
18162306a36Sopenharmony_ci	.vp_vstepmin		= OMAP4_VP_VSTEPMIN_VSTEPMIN,
18262306a36Sopenharmony_ci	.vp_vstepmax		= OMAP4_VP_VSTEPMAX_VSTEPMAX,
18362306a36Sopenharmony_ci	.vddmin			= 0,
18462306a36Sopenharmony_ci	.vddmax			= 2100000,
18562306a36Sopenharmony_ci	.vp_timeout_us		= OMAP4_VP_VLIMITTO_TIMEOUT_US,
18662306a36Sopenharmony_ci	.i2c_slave_addr		= OMAP4_SRI2C_SLAVE_ADDR,
18762306a36Sopenharmony_ci	.volt_reg_addr		= OMAP4_VDD_IVA_SR_VOLT_REG,
18862306a36Sopenharmony_ci	.cmd_reg_addr		= OMAP4_VDD_IVA_SR_CMD_REG,
18962306a36Sopenharmony_ci	.i2c_high_speed		= true,
19062306a36Sopenharmony_ci	.i2c_pad_load		= 3,
19162306a36Sopenharmony_ci	.vsel_to_uv		= twl6030_vsel_to_uv,
19262306a36Sopenharmony_ci	.uv_to_vsel		= twl6030_uv_to_vsel,
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap4_core_pmic = {
19662306a36Sopenharmony_ci	.slew_rate		= 4000,
19762306a36Sopenharmony_ci	.step_size		= 12660,
19862306a36Sopenharmony_ci	.vp_erroroffset		= OMAP4_VP_CONFIG_ERROROFFSET,
19962306a36Sopenharmony_ci	.vp_vstepmin		= OMAP4_VP_VSTEPMIN_VSTEPMIN,
20062306a36Sopenharmony_ci	.vp_vstepmax		= OMAP4_VP_VSTEPMAX_VSTEPMAX,
20162306a36Sopenharmony_ci	.vddmin			= 0,
20262306a36Sopenharmony_ci	.vddmax			= 2100000,
20362306a36Sopenharmony_ci	.vp_timeout_us		= OMAP4_VP_VLIMITTO_TIMEOUT_US,
20462306a36Sopenharmony_ci	.i2c_slave_addr		= OMAP4_SRI2C_SLAVE_ADDR,
20562306a36Sopenharmony_ci	.volt_reg_addr		= OMAP4_VDD_CORE_SR_VOLT_REG,
20662306a36Sopenharmony_ci	.cmd_reg_addr		= OMAP4_VDD_CORE_SR_CMD_REG,
20762306a36Sopenharmony_ci	.i2c_high_speed		= true,
20862306a36Sopenharmony_ci	.i2c_pad_load		= 3,
20962306a36Sopenharmony_ci	.vsel_to_uv		= twl6030_vsel_to_uv,
21062306a36Sopenharmony_ci	.uv_to_vsel		= twl6030_uv_to_vsel,
21162306a36Sopenharmony_ci};
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ciint __init omap4_twl_init(void)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	struct voltagedomain *voltdm;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	if (!cpu_is_omap44xx() ||
21862306a36Sopenharmony_ci	    of_find_compatible_node(NULL, NULL, "motorola,cpcap"))
21962306a36Sopenharmony_ci		return -ENODEV;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	voltdm = voltdm_lookup("mpu");
22262306a36Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap4_mpu_pmic);
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	voltdm = voltdm_lookup("iva");
22562306a36Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap4_iva_pmic);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	voltdm = voltdm_lookup("core");
22862306a36Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap4_core_pmic);
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return 0;
23162306a36Sopenharmony_ci}
23262306a36Sopenharmony_ci
23362306a36Sopenharmony_ciint __init omap3_twl_init(void)
23462306a36Sopenharmony_ci{
23562306a36Sopenharmony_ci	struct voltagedomain *voltdm;
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_ci	if (!cpu_is_omap34xx())
23862306a36Sopenharmony_ci		return -ENODEV;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	voltdm = voltdm_lookup("mpu_iva");
24162306a36Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap3_mpu_pmic);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	voltdm = voltdm_lookup("core");
24462306a36Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap3_core_pmic);
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	return 0;
24762306a36Sopenharmony_ci}
248