162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * pmic-cpcap.c - CPCAP-specific functions for the OPP code
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Adapted from Motorola Mapphone Android Linux kernel
662306a36Sopenharmony_ci * Copyright (C) 2011 Motorola, Inc.
762306a36Sopenharmony_ci */
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/err.h>
1062306a36Sopenharmony_ci#include <linux/io.h>
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "soc.h"
1462306a36Sopenharmony_ci#include "pm.h"
1562306a36Sopenharmony_ci#include "voltage.h"
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <linux/init.h>
1862306a36Sopenharmony_ci#include "vc.h"
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/**
2162306a36Sopenharmony_ci * omap_cpcap_vsel_to_vdc - convert CPCAP VSEL value to microvolts DC
2262306a36Sopenharmony_ci * @vsel: CPCAP VSEL value to convert
2362306a36Sopenharmony_ci *
2462306a36Sopenharmony_ci * Returns the microvolts DC that the CPCAP PMIC should generate when
2562306a36Sopenharmony_ci * programmed with @vsel.
2662306a36Sopenharmony_ci */
2762306a36Sopenharmony_cistatic unsigned long omap_cpcap_vsel_to_uv(unsigned char vsel)
2862306a36Sopenharmony_ci{
2962306a36Sopenharmony_ci	if (vsel > 0x44)
3062306a36Sopenharmony_ci		vsel = 0x44;
3162306a36Sopenharmony_ci	return (((vsel * 125) + 6000)) * 100;
3262306a36Sopenharmony_ci}
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/**
3562306a36Sopenharmony_ci * omap_cpcap_uv_to_vsel - convert microvolts DC to CPCAP VSEL value
3662306a36Sopenharmony_ci * @uv: microvolts DC to convert
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci * Returns the VSEL value necessary for the CPCAP PMIC to
3962306a36Sopenharmony_ci * generate an output voltage equal to or greater than @uv microvolts DC.
4062306a36Sopenharmony_ci */
4162306a36Sopenharmony_cistatic unsigned char omap_cpcap_uv_to_vsel(unsigned long uv)
4262306a36Sopenharmony_ci{
4362306a36Sopenharmony_ci	if (uv < 600000)
4462306a36Sopenharmony_ci		uv = 600000;
4562306a36Sopenharmony_ci	else if (uv > 1450000)
4662306a36Sopenharmony_ci		uv = 1450000;
4762306a36Sopenharmony_ci	return DIV_ROUND_UP(uv - 600000, 12500);
4862306a36Sopenharmony_ci}
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap_cpcap_core = {
5162306a36Sopenharmony_ci	.slew_rate = 4000,
5262306a36Sopenharmony_ci	.step_size = 12500,
5362306a36Sopenharmony_ci	.vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
5462306a36Sopenharmony_ci	.vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
5562306a36Sopenharmony_ci	.vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
5662306a36Sopenharmony_ci	.vddmin = 900000,
5762306a36Sopenharmony_ci	.vddmax = 1350000,
5862306a36Sopenharmony_ci	.vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
5962306a36Sopenharmony_ci	.i2c_slave_addr = 0x02,
6062306a36Sopenharmony_ci	.volt_reg_addr = 0x00,
6162306a36Sopenharmony_ci	.cmd_reg_addr = 0x01,
6262306a36Sopenharmony_ci	.i2c_high_speed = false,
6362306a36Sopenharmony_ci	.vsel_to_uv = omap_cpcap_vsel_to_uv,
6462306a36Sopenharmony_ci	.uv_to_vsel = omap_cpcap_uv_to_vsel,
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap_cpcap_iva = {
6862306a36Sopenharmony_ci	.slew_rate = 4000,
6962306a36Sopenharmony_ci	.step_size = 12500,
7062306a36Sopenharmony_ci	.vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
7162306a36Sopenharmony_ci	.vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
7262306a36Sopenharmony_ci	.vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
7362306a36Sopenharmony_ci	.vddmin = 900000,
7462306a36Sopenharmony_ci	.vddmax = 1375000,
7562306a36Sopenharmony_ci	.vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
7662306a36Sopenharmony_ci	.i2c_slave_addr = 0x44,
7762306a36Sopenharmony_ci	.volt_reg_addr = 0x0,
7862306a36Sopenharmony_ci	.cmd_reg_addr = 0x01,
7962306a36Sopenharmony_ci	.i2c_high_speed = false,
8062306a36Sopenharmony_ci	.vsel_to_uv = omap_cpcap_vsel_to_uv,
8162306a36Sopenharmony_ci	.uv_to_vsel = omap_cpcap_uv_to_vsel,
8262306a36Sopenharmony_ci};
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_ci/**
8562306a36Sopenharmony_ci * omap_max8952_vsel_to_vdc - convert MAX8952 VSEL value to microvolts DC
8662306a36Sopenharmony_ci * @vsel: MAX8952 VSEL value to convert
8762306a36Sopenharmony_ci *
8862306a36Sopenharmony_ci * Returns the microvolts DC that the MAX8952 Regulator should generate when
8962306a36Sopenharmony_ci * programmed with @vsel.
9062306a36Sopenharmony_ci */
9162306a36Sopenharmony_cistatic unsigned long omap_max8952_vsel_to_uv(unsigned char vsel)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci	if (vsel > 0x3F)
9462306a36Sopenharmony_ci		vsel = 0x3F;
9562306a36Sopenharmony_ci	return (((vsel * 100) + 7700)) * 100;
9662306a36Sopenharmony_ci}
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci/**
9962306a36Sopenharmony_ci * omap_max8952_uv_to_vsel - convert microvolts DC to MAX8952 VSEL value
10062306a36Sopenharmony_ci * @uv: microvolts DC to convert
10162306a36Sopenharmony_ci *
10262306a36Sopenharmony_ci * Returns the VSEL value necessary for the MAX8952 Regulator to
10362306a36Sopenharmony_ci * generate an output voltage equal to or greater than @uv microvolts DC.
10462306a36Sopenharmony_ci */
10562306a36Sopenharmony_cistatic unsigned char omap_max8952_uv_to_vsel(unsigned long uv)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	if (uv < 770000)
10862306a36Sopenharmony_ci		uv = 770000;
10962306a36Sopenharmony_ci	else if (uv > 1400000)
11062306a36Sopenharmony_ci		uv = 1400000;
11162306a36Sopenharmony_ci	return DIV_ROUND_UP(uv - 770000, 10000);
11262306a36Sopenharmony_ci}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap443x_max8952_mpu = {
11562306a36Sopenharmony_ci	.slew_rate = 16000,
11662306a36Sopenharmony_ci	.step_size = 10000,
11762306a36Sopenharmony_ci	.vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
11862306a36Sopenharmony_ci	.vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
11962306a36Sopenharmony_ci	.vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
12062306a36Sopenharmony_ci	.vddmin = 900000,
12162306a36Sopenharmony_ci	.vddmax = 1400000,
12262306a36Sopenharmony_ci	.vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
12362306a36Sopenharmony_ci	.i2c_slave_addr = 0x60,
12462306a36Sopenharmony_ci	.volt_reg_addr = 0x03,
12562306a36Sopenharmony_ci	.cmd_reg_addr = 0x03,
12662306a36Sopenharmony_ci	.i2c_high_speed = false,
12762306a36Sopenharmony_ci	.vsel_to_uv = omap_max8952_vsel_to_uv,
12862306a36Sopenharmony_ci	.uv_to_vsel = omap_max8952_uv_to_vsel,
12962306a36Sopenharmony_ci};
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci/**
13262306a36Sopenharmony_ci * omap_fan5355_vsel_to_vdc - convert FAN535503 VSEL value to microvolts DC
13362306a36Sopenharmony_ci * @vsel: FAN535503 VSEL value to convert
13462306a36Sopenharmony_ci *
13562306a36Sopenharmony_ci * Returns the microvolts DC that the FAN535503 Regulator should generate when
13662306a36Sopenharmony_ci * programmed with @vsel.
13762306a36Sopenharmony_ci */
13862306a36Sopenharmony_cistatic unsigned long omap_fan535503_vsel_to_uv(unsigned char vsel)
13962306a36Sopenharmony_ci{
14062306a36Sopenharmony_ci	/* Extract bits[5:0] */
14162306a36Sopenharmony_ci	vsel &= 0x3F;
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	return (((vsel * 125) + 7500)) * 100;
14462306a36Sopenharmony_ci}
14562306a36Sopenharmony_ci
14662306a36Sopenharmony_ci/**
14762306a36Sopenharmony_ci * omap_fan535508_vsel_to_vdc - convert FAN535508 VSEL value to microvolts DC
14862306a36Sopenharmony_ci * @vsel: FAN535508 VSEL value to convert
14962306a36Sopenharmony_ci *
15062306a36Sopenharmony_ci * Returns the microvolts DC that the FAN535508 Regulator should generate when
15162306a36Sopenharmony_ci * programmed with @vsel.
15262306a36Sopenharmony_ci */
15362306a36Sopenharmony_cistatic unsigned long omap_fan535508_vsel_to_uv(unsigned char vsel)
15462306a36Sopenharmony_ci{
15562306a36Sopenharmony_ci	/* Extract bits[5:0] */
15662306a36Sopenharmony_ci	vsel &= 0x3F;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (vsel > 0x37)
15962306a36Sopenharmony_ci		vsel = 0x37;
16062306a36Sopenharmony_ci	return (((vsel * 125) + 7500)) * 100;
16162306a36Sopenharmony_ci}
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci/**
16562306a36Sopenharmony_ci * omap_fan535503_uv_to_vsel - convert microvolts DC to FAN535503 VSEL value
16662306a36Sopenharmony_ci * @uv: microvolts DC to convert
16762306a36Sopenharmony_ci *
16862306a36Sopenharmony_ci * Returns the VSEL value necessary for the MAX8952 Regulator to
16962306a36Sopenharmony_ci * generate an output voltage equal to or greater than @uv microvolts DC.
17062306a36Sopenharmony_ci */
17162306a36Sopenharmony_cistatic unsigned char omap_fan535503_uv_to_vsel(unsigned long uv)
17262306a36Sopenharmony_ci{
17362306a36Sopenharmony_ci	unsigned char vsel;
17462306a36Sopenharmony_ci	if (uv < 750000)
17562306a36Sopenharmony_ci		uv = 750000;
17662306a36Sopenharmony_ci	else if (uv > 1537500)
17762306a36Sopenharmony_ci		uv = 1537500;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	vsel = DIV_ROUND_UP(uv - 750000, 12500);
18062306a36Sopenharmony_ci	return vsel | 0xC0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_ci/**
18462306a36Sopenharmony_ci * omap_fan535508_uv_to_vsel - convert microvolts DC to FAN535508 VSEL value
18562306a36Sopenharmony_ci * @uv: microvolts DC to convert
18662306a36Sopenharmony_ci *
18762306a36Sopenharmony_ci * Returns the VSEL value necessary for the MAX8952 Regulator to
18862306a36Sopenharmony_ci * generate an output voltage equal to or greater than @uv microvolts DC.
18962306a36Sopenharmony_ci */
19062306a36Sopenharmony_cistatic unsigned char omap_fan535508_uv_to_vsel(unsigned long uv)
19162306a36Sopenharmony_ci{
19262306a36Sopenharmony_ci	unsigned char vsel;
19362306a36Sopenharmony_ci	if (uv < 750000)
19462306a36Sopenharmony_ci		uv = 750000;
19562306a36Sopenharmony_ci	else if (uv > 1437500)
19662306a36Sopenharmony_ci		uv = 1437500;
19762306a36Sopenharmony_ci
19862306a36Sopenharmony_ci	vsel = DIV_ROUND_UP(uv - 750000, 12500);
19962306a36Sopenharmony_ci	return vsel | 0xC0;
20062306a36Sopenharmony_ci}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci/* fan5335-core */
20362306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap4_fan_core = {
20462306a36Sopenharmony_ci	.slew_rate = 4000,
20562306a36Sopenharmony_ci	.step_size = 12500,
20662306a36Sopenharmony_ci	.vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
20762306a36Sopenharmony_ci	.vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
20862306a36Sopenharmony_ci	.vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
20962306a36Sopenharmony_ci	.vddmin = 850000,
21062306a36Sopenharmony_ci	.vddmax = 1375000,
21162306a36Sopenharmony_ci	.vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
21262306a36Sopenharmony_ci	.i2c_slave_addr = 0x4A,
21362306a36Sopenharmony_ci	.i2c_high_speed = false,
21462306a36Sopenharmony_ci	.volt_reg_addr = 0x01,
21562306a36Sopenharmony_ci	.cmd_reg_addr = 0x01,
21662306a36Sopenharmony_ci	.vsel_to_uv = omap_fan535508_vsel_to_uv,
21762306a36Sopenharmony_ci	.uv_to_vsel = omap_fan535508_uv_to_vsel,
21862306a36Sopenharmony_ci};
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci/* fan5335 iva */
22162306a36Sopenharmony_cistatic struct omap_voltdm_pmic omap4_fan_iva = {
22262306a36Sopenharmony_ci	.slew_rate = 4000,
22362306a36Sopenharmony_ci	.step_size = 12500,
22462306a36Sopenharmony_ci	.vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET,
22562306a36Sopenharmony_ci	.vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN,
22662306a36Sopenharmony_ci	.vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX,
22762306a36Sopenharmony_ci	.vddmin = 850000,
22862306a36Sopenharmony_ci	.vddmax = 1375000,
22962306a36Sopenharmony_ci	.vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US,
23062306a36Sopenharmony_ci	.i2c_slave_addr = 0x48,
23162306a36Sopenharmony_ci	.volt_reg_addr = 0x01,
23262306a36Sopenharmony_ci	.cmd_reg_addr = 0x01,
23362306a36Sopenharmony_ci	.i2c_high_speed = false,
23462306a36Sopenharmony_ci	.vsel_to_uv = omap_fan535503_vsel_to_uv,
23562306a36Sopenharmony_ci	.uv_to_vsel = omap_fan535503_uv_to_vsel,
23662306a36Sopenharmony_ci};
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ciint __init omap4_cpcap_init(void)
23962306a36Sopenharmony_ci{
24062306a36Sopenharmony_ci	struct voltagedomain *voltdm;
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci	if (!of_find_compatible_node(NULL, NULL, "motorola,cpcap"))
24362306a36Sopenharmony_ci		return -ENODEV;
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	voltdm = voltdm_lookup("mpu");
24662306a36Sopenharmony_ci	omap_voltage_register_pmic(voltdm, &omap443x_max8952_mpu);
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	if (of_machine_is_compatible("motorola,droid-bionic")) {
24962306a36Sopenharmony_ci		voltdm = voltdm_lookup("core");
25062306a36Sopenharmony_ci		omap_voltage_register_pmic(voltdm, &omap_cpcap_core);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci		voltdm = voltdm_lookup("iva");
25362306a36Sopenharmony_ci		omap_voltage_register_pmic(voltdm, &omap_cpcap_iva);
25462306a36Sopenharmony_ci	} else {
25562306a36Sopenharmony_ci		voltdm = voltdm_lookup("core");
25662306a36Sopenharmony_ci		omap_voltage_register_pmic(voltdm, &omap4_fan_core);
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_ci		voltdm = voltdm_lookup("iva");
25962306a36Sopenharmony_ci		omap_voltage_register_pmic(voltdm, &omap4_fan_iva);
26062306a36Sopenharmony_ci	}
26162306a36Sopenharmony_ci
26262306a36Sopenharmony_ci	return 0;
26362306a36Sopenharmony_ci}
26462306a36Sopenharmony_ci
26562306a36Sopenharmony_cistatic int __init cpcap_late_init(void)
26662306a36Sopenharmony_ci{
26762306a36Sopenharmony_ci	omap4_vc_set_pmic_signaling(PWRDM_POWER_RET);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	return 0;
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ciomap_late_initcall(cpcap_late_init);
272