blob: 9f3181bcf55fa44b80ac0fd3ccf6cb38c71b4b40 [file] [log] [blame]
/*
* NDA AND NEED-TO-KNOW REQUIRED
*
* Copyright © 2013-2018 Synaptics Incorporated. All rights reserved.
*
* This file contains information that is proprietary to Synaptics
* Incorporated ("Synaptics"). The holder of this file shall treat all
* information contained herein as confidential, shall use the
* information only for its intended purpose, and shall not duplicate,
* disclose, or disseminate any of this information in any manner
* unless Synaptics has otherwise provided express, written
* permission.
*
* Use of the materials may require a license of intellectual property
* from a third party or from Synaptics. This file conveys no express
* or implied licenses to any intellectual property rights belonging
* to Synaptics.
*
* INFORMATION CONTAINED IN THIS DOCUMENT IS PROVIDED "AS-IS," AND
* SYNAPTICS EXPRESSLY DISCLAIMS ALL EXPRESS AND IMPLIED WARRANTIES,
* INCLUDING ANY IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE, AND ANY WARRANTIES OF NON-INFRINGEMENT OF ANY
* INTELLECTUAL PROPERTY RIGHTS. IN NO EVENT SHALL SYNAPTICS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, PUNITIVE, OR
* CONSEQUENTIAL DAMAGES ARISING OUT OF OR IN CONNECTION WITH THE USE
* OF THE INFORMATION CONTAINED IN THIS DOCUMENT, HOWEVER CAUSED AND
* BASED ON ANY THEORY OF LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* NEGLIGENCE OR OTHER TORTIOUS ACTION, AND EVEN IF SYNAPTICS WAS
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. IF A TRIBUNAL OF
* COMPETENT JURISDICTION DOES NOT PERMIT THE DISCLAIMER OF DIRECT
* DAMAGES OR ANY OTHER DAMAGES, SYNAPTICS' TOTAL CUMULATIVE LIABILITY
* TO ANY PARTY SHALL NOT EXCEED ONE HUNDRED U.S. DOLLARS.
*/
#include "i2c_driver.h"
#include "global.h"
#include "io.h"
#include "debug.h"
#include "memmap.h"
#include "chip_voltage_info.h"
#include "SysMgr.h"
#include "apbRegBase.h"
#include "apb_timer.h"
#include "lgpl_printf.h"
#include "pv_comp.h"
extern void delay_ms(unsigned int ms);
#ifndef VOUT_CPU_ID
#define VOUT_CPU_ID (2)
#endif
#ifndef VOUT_CORE_ID
#define VOUT_CORE_ID (0)
#endif
#ifndef VOUT_CPU_CHANNEL
#define VOUT_CPU_CHANNEL (0)
#endif
#ifndef VOUT_CORE_CHANNEL
#define VOUT_CORE_CHANNEL (1)
#endif
// all defined under uv
#ifndef MINIMAL_VOL_STEP_SY20278
#define MINIMAL_VOL_STEP_SY20278 12500
#endif
#define MIN_VOLTAGE 762500
#define MAX_VOLTAGE 1050000
#define SLAVE_ADDR 0x61
#define RSVD 0xFFFFFFFF
#define REG_VSEL0 0x0
extern void udelay(unsigned long usec);
extern int i2c_master_init(int id, int speed, int b_10bit_addr);
extern int i2c_master_write_and_read(int id, int target_addr, unsigned char* send_buff, int send_len, unsigned char* recv_buff, int recv_len);
static int pmic_volt2data(int volt, int *p_data)
{
unsigned int data;
if ((volt >= MIN_VOLTAGE) && (volt <= MAX_VOLTAGE))
data = (volt - MIN_VOLTAGE) / 12500;
else
data = RSVD;
if (data == RSVD)
return -1;
else {
*p_data = data;
return 0;
}
return 0;
}
static int pmic_data2volt(int *p_volt, int vdata)
{
unsigned int vol;
int data = vdata;
data = data & 0x3F;
if (data <= 0x3f && 0x17 <= data)
vol = MAX_VOLTAGE;
else if (data < 0x17)
vol = MIN_VOLTAGE + data * 12500;
else
vol = RSVD;
if (vol == RSVD)
return -1;
else {
*p_volt = vol;
return 0;
}
return 0;
}
static int sy20278_set_vol(int master_id, int slaveAddr, int volt)
{
int target = volt, vdata = 0;
unsigned char buff[2];
unsigned char data_reg0, data;
unsigned int bulk_reg0 = REG_VSEL0;
int ret = 1;
// read, sy20278 slave address is 0x61
i2c_master_init(master_id, 100, 0); //int id, int speed, int b_10bit_addr
ret = i2c_master_write_and_read(master_id, slaveAddr, (unsigned char*)&bulk_reg0, 1, (unsigned char*)&data_reg0, 1);
if (ret)
{
lgpl_printf("PMIC i2c read fail !\n");
return ret;
}
data_reg0 = data_reg0 & 0xc0;
ret = pmic_volt2data(target, &vdata);
if (ret == 0) {
data_reg0 = data_reg0 | (unsigned char)vdata;
lgpl_printf( "data_reg0 = 0x%x \n", data_reg0);
buff[0] = (unsigned char)REG_VSEL0;
buff[1] = (unsigned char)data_reg0;
//i2c_master_init(master_id, 100, 0);
// write
ret = i2c_master_write_and_read(master_id, slaveAddr, buff, 2, (unsigned char*)0, 0);
if (ret) {
lgpl_printf("PMIC i2c write fail !\n");
return ret;
}
//i2c_master_init(master_id, 100, 0); //int id, int speed, int b_10bit_addr
// read
buff[0] = (unsigned char)REG_VSEL0;
ret = i2c_master_write_and_read(master_id, slaveAddr, buff, 1, (unsigned char *)&data, 1);
if (ret) {
lgpl_printf("PMIC i2c read fail !\n");
return ret;
}
if (data_reg0 != data) {
lgpl_printf( "PMIC sy20278: read:0x%02x != write:0x%02x\n", data, data_reg0);
return -1;
}
lgpl_printf( "set to %d mv\n", target);
delay_ms(1);
}
else {
lgpl_printf( "Illegal target voltage for PMIC sy20278 !\n");
return -1;
}
return ret;
}
static int sy20278_get_vol(int master_id, int slaveAddr)
{
int read = 0xff;
int volt;
unsigned int bulk_reg = REG_VSEL0;
int ret = 1;
i2c_master_init(master_id, 100, 0); //int id, int speed, int b_10bit_addr
// read, sy20278 slave address is 0x61
ret = i2c_master_write_and_read(master_id, slaveAddr, (unsigned char*)&bulk_reg, 1, (unsigned char*)&read, 1);
lgpl_printf( "\nREG_VSEL0 = 0x%x \n", read);
ret |= pmic_data2volt(&volt, read);
if(ret) {
lgpl_printf(" i2c read fail\n");
return -1;
}
return volt;
}
static int i2c_get_cpu_volt(void)
{
int volt = sy20278_get_vol(VOUT_CPU_ID, SLAVE_ADDR);
if(volt < 0)
return 0;
return volt;
}
static int i2c_get_core_volt(void)
{
int volt = sy20278_get_vol(VOUT_CORE_ID, SLAVE_ADDR);
if(volt < 0)
return 0;
return volt;
}
static int i2c_set_volt(int master_id, int from, int to)
{
int volt = from;
while (volt != to){
if (volt > to){
volt -= MINIMAL_VOL_STEP_SY20278;
if (volt < to)
volt = to;
}else{
volt += MINIMAL_VOL_STEP_SY20278;
if (volt > to)
volt = to;
}
if(0 != sy20278_set_vol(master_id, SLAVE_ADDR, volt))
return 1;
//udelay(50); //FIXME: 1ms delayed
}
return 0;
}
static int i2c_set_vcpu_volt(int from, int to)
{
return i2c_set_volt(VOUT_CPU_ID, from ,to);
}
static int i2c_set_vcore_volt(int from, int to)
{
return i2c_set_volt(VOUT_CORE_ID, from ,to);
}
const dvfs_ops_t sy20278_ops = {
.get_vcpu_volt = i2c_get_cpu_volt,
.get_vcore_volt = i2c_get_core_volt,
.set_vcpu_volt = i2c_set_vcpu_volt,
.set_vcore_volt =i2c_set_vcore_volt
};