blob: 92be66debc152447b26e94ad4189bd3f5c0a1467 [file] [log] [blame]
/*
* muic_regmap_max77865.c
*
* Copyright (C) 2016 Samsung Electronics
* Insun Choi <insun77.choi@samsung.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/gpio.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/host_notify.h>
#include <linux/string.h>
#include <linux/muic/muic.h>
#if defined(CONFIG_MUIC_NOTIFIER)
#include <linux/muic/muic_notifier.h>
#endif /* CONFIG_MUIC_NOTIFIER */
#if defined(CONFIG_OF)
#include <linux/of_device.h>
#include <linux/of_gpio.h>
#endif /* CONFIG_OF */
#include "muic-internal.h"
#include "muic_i2c.h"
#include "muic_regmap.h"
/* Control2 Initialization */
#define INIT_CONTROL2 (0x00)
/*
Control4 Initialization value : 00_1_1_0000
[7:6] RSVD
[5] FacAuto, 1:Factory Auto detectioni Enabled
[4] USBAuto, 1:USB Auto detection Enabled(valid only if AccDet=1)
[3:0] RSVD
*/
#define INIT_CONTROL4 (0x30)
/* Workaround for CL65 */
#define INIT_CCDET (0x00)
/* max77865 I2C registers */
enum max77865_muic_reg {
REG_ID = 0x00,
REG_INT_MAIN = 0x01,
REG_INT_BC = 0x02,
REG_INT_FC = 0x03,
REG_INT_GP = 0x04,
REG_INTMASK_MAIN = 0x07,
REG_INTMASK_BC = 0x08,
REG_INTMASK_FC = 0x09,
REG_INTMASK_GP = 0x0A,
REG_STATUS1_BC = 0x0D,
REG_STATUS2_BC = 0x0E,
REG_STATUS_GP = 0x0F,
REG_CONTROL1_BC = 0x13,
REG_CONTROL2_BC = 0x14,
REG_CCDET = 0x15,
REG_CONTROL1 = 0x19,
REG_CONTROL2 = 0x1A,
REG_CONTROL3 = 0x1B,
REG_CONTROL4 = 0x1C,
REG_HVCONTROL1 = 0x1D,
REG_HVCONTROL2 = 0x1E,
REG_END,
};
/* UID table */
typedef enum {
UID_JIG_USB_ON = 0x0, /* 301Kohm */
UID_JIG_UART_OFF = 0x1, /* 523Kohm */
UID_RSVD = 0x2,
UID_OPEN = 0x3,
} muic_uid_t;
#define REG_ITEM(addr, bitp, mask) ((bitp<<16) | (mask<<8) | addr)
/* Field */
enum max77865_muic_reg_item {
ID_CHIP_REV = REG_ITEM(REG_ID, _BIT0, _MASK8),
INT_MAIN_GP = REG_ITEM(REG_INT_MAIN, _BIT4, _MASK1),
INT_MAIN_FC = REG_ITEM(REG_INT_MAIN, _BIT3, _MASK1),
INT_MAIN_BC = REG_ITEM(REG_INT_MAIN, _BIT1, _MASK1),
INT_BC_VBVolt = REG_ITEM(REG_INT_BC, _BIT7, _MASK1),
INT_BC_DxOVP = REG_ITEM(REG_INT_BC, _BIT6, _MASK1),
INT_BC_DNVDATREF = REG_ITEM(REG_INT_BC, _BIT5, _MASK1), /* = VDNMon */
INT_BC_ChgDetRunF = REG_ITEM(REG_INT_BC, _BIT4, _MASK1), /* Falling edge */
INT_BC_ChgDetRunR = REG_ITEM(REG_INT_BC, _BIT3, _MASK1), /* Rising edge */
INT_BC_PrChgTyp = REG_ITEM(REG_INT_BC, _BIT2, _MASK1),
INT_BC_DCDTmr = REG_ITEM(REG_INT_BC, _BIT1, _MASK1),
INT_BC_ChgTyp = REG_ITEM(REG_INT_BC, _BIT0, _MASK1),
INT_FC_MRxRdy = REG_ITEM(REG_INT_FC, _BIT7, _MASK1),
INT_FC_MRxPerr = REG_ITEM(REG_INT_FC, _BIT6, _MASK1),
INT_FC_MRxTrf = REG_ITEM(REG_INT_FC, _BIT5, _MASK1),
INT_FC_MRxBufOw = REG_ITEM(REG_INT_FC, _BIT4, _MASK1),
INT_FC_MPNack = REG_ITEM(REG_INT_FC, _BIT3, _MASK1),
INT_FC_MPGDone = REG_ITEM(REG_INT_FC, _BIT2, _MASK1),
INT_GP_UIDGND = REG_ITEM(REG_INT_GP, _BIT4, _MASK1),
INT_GP_TSHUT = REG_ITEM(REG_INT_GP, _BIT3, _MASK1),
INT_GP_VbADC = REG_ITEM(REG_INT_GP, _BIT2, _MASK1),
INT_GP_RST = REG_ITEM(REG_INT_GP, _BIT1, _MASK1),
INT_GP_UID = REG_ITEM(REG_INT_GP, _BIT0, _MASK1),
INTMASK_MAIN_GP = REG_ITEM(REG_INTMASK_MAIN, _BIT4, _MASK1),
INTMASK_MAIN_FC = REG_ITEM(REG_INTMASK_MAIN, _BIT3, _MASK1),
INTMASK_MAIN_BC = REG_ITEM(REG_INTMASK_MAIN, _BIT1, _MASK1),
INTMASK_BC_VBVolt = REG_ITEM(REG_INTMASK_BC, _BIT7, _MASK1),
INTMASK_BC_DxOVP = REG_ITEM(REG_INTMASK_BC, _BIT6, _MASK1),
INTMASK_BC_DNVDATREF = REG_ITEM(REG_INTMASK_BC, _BIT5, _MASK1),
INTMASK_BC_ChgDetRunF = REG_ITEM(REG_INTMASK_BC, _BIT4, _MASK1),
INTMASK_BC_ChgDetRunR = REG_ITEM(REG_INTMASK_BC, _BIT3, _MASK1),
INTMASK_BC_PrChgTyp = REG_ITEM(REG_INTMASK_BC, _BIT2, _MASK1),
INTMASK_BC_DCDTmr = REG_ITEM(REG_INTMASK_BC, _BIT1, _MASK1),
INTMASK_BC_ChgTyp = REG_ITEM(REG_INTMASK_BC, _BIT0, _MASK1),
INTMASK_FC_MRxRdy = REG_ITEM(REG_INTMASK_FC, _BIT7, _MASK1),
INTMASK_FC_MRxPerr = REG_ITEM(REG_INTMASK_FC, _BIT6, _MASK1),
INTMASK_FC_MRxTrf = REG_ITEM(REG_INTMASK_FC, _BIT5, _MASK1),
INTMASK_FC_MRxBufOw = REG_ITEM(REG_INTMASK_FC, _BIT4, _MASK1),
INTMASK_FC_MPNack = REG_ITEM(REG_INTMASK_FC, _BIT3, _MASK1),
INTMASK_FC_MPGDone = REG_ITEM(REG_INTMASK_FC, _BIT2, _MASK1),
INTMASK_GP_UIDGND = REG_ITEM(REG_INTMASK_GP, _BIT4, _MASK1),
INTMASK_GP_TSHUT = REG_ITEM(REG_INTMASK_GP, _BIT3, _MASK1),
INTMASK_GP_VbADC = REG_ITEM(REG_INTMASK_GP, _BIT2, _MASK1),
INTMASK_GP_RST = REG_ITEM(REG_INTMASK_GP, _BIT1, _MASK1),
INTMASK_GP_UID = REG_ITEM(REG_INTMASK_GP, _BIT0, _MASK1),
STATUS1_BC_VBVolt = REG_ITEM(REG_STATUS1_BC, _BIT7, _MASK1),
STATUS1_BC_ChgDetRun = REG_ITEM(REG_STATUS1_BC, _BIT6, _MASK1),
STATUS1_BC_PrChgTyp = REG_ITEM(REG_STATUS1_BC, _BIT3, _MASK3),
STATUS1_BC_DCDTmr = REG_ITEM(REG_STATUS1_BC, _BIT2, _MASK1),
STATUS1_BC_ChgTyp = REG_ITEM(REG_STATUS1_BC, _BIT0, _MASK2),
STATUS2_BC_DxOVP = REG_ITEM(REG_STATUS2_BC, _BIT1, _MASK1),
STATUS2_BC_DNVDATREF = REG_ITEM(REG_STATUS2_BC, _BIT0, _MASK1),
STATUS_GP_UID = REG_ITEM(REG_STATUS_GP, _BIT6, _MASK2),
STATUS_GP_UIDGND = REG_ITEM(REG_STATUS_GP, _BIT5, _MASK1),
STATUS_GP_TSHUT = REG_ITEM(REG_STATUS_GP, _BIT4, _MASK1),
STATUS_GP_VbADC = REG_ITEM(REG_STATUS_GP, _BIT0, _MASK4),
CONTROL1_BC_DCDCpl = REG_ITEM(REG_CONTROL1_BC, _BIT7, _MASK1),
CONTROL1_BC_UIDEn = REG_ITEM(REG_CONTROL1_BC, _BIT6, _MASK1),
CONTROL1_BC_NoAutoIBUS = REG_ITEM(REG_CONTROL1_BC, _BIT5, _MASK1),
CONTROL1_BC_3ADCPDet = REG_ITEM(REG_CONTROL1_BC, _BIT4, _MASK1),
CONTROL1_BC_SfOutCtrl = REG_ITEM(REG_CONTROL1_BC, _BIT2, _MASK2),
CONTROL1_BC_ChgDetMan = REG_ITEM(REG_CONTROL1_BC, _BIT1, _MASK1),
CONTROL1_BC_ChgDetEn = REG_ITEM(REG_CONTROL1_BC, _BIT0, _MASK1),
CONTROL2_BC_DNMonEn = REG_ITEM(REG_CONTROL2_BC, _BIT5, _MASK1),
CONTROL2_BC_DPDNMan = REG_ITEM(REG_CONTROL2_BC, _BIT4, _MASK1),
CONTROL2_BC_DPDrv = REG_ITEM(REG_CONTROL2_BC, _BIT2, _MASK2),
CONTROL2_BC_DNDrv = REG_ITEM(REG_CONTROL2_BC, _BIT0, _MASK2),
CONTROL1_NoBCComp = REG_ITEM(REG_CONTROL1, _BIT7, _MASK1),
CONTROL1_RCPS = REG_ITEM(REG_CONTROL1, _BIT6, _MASK1),
CONTROL1_COMP2Sw = REG_ITEM(REG_CONTROL1, _BIT3, _MASK3),
CONTROL1_COMN1Sw = REG_ITEM(REG_CONTROL1, _BIT0, _MASK3),
CONTROL2_CPEn = REG_ITEM(REG_CONTROL2, _BIT2, _MASK1),
CONTROL2_CHGEnCtrl = REG_ITEM(REG_CONTROL2, _BIT1, _MASK1),
CONTROL3_RES3Set = REG_ITEM(REG_CONTROL3, _BIT5, _MASK1),
CONTROL3_RES2Set = REG_ITEM(REG_CONTROL3, _BIT3, _MASK2),
CONTROL3_RES1Set = REG_ITEM(REG_CONTROL3, _BIT1, _MASK2),
CONTROL3_JIGSet = REG_ITEM(REG_CONTROL3, _BIT0, _MASK1),
CONTROL4_FctAuto = REG_ITEM(REG_CONTROL4, _BIT5, _MASK1),
CONTROL4_USBAuto = REG_ITEM(REG_CONTROL4, _BIT4, _MASK1),
HVCONTROL1_VbusADCEn = REG_ITEM(REG_HVCONTROL1, _BIT0, _MASK1),
HVCONTROL2_FCRXDebEn = REG_ITEM(REG_HVCONTROL2, _BIT7, _MASK1),
HVCONTROL2_MPngEnb = REG_ITEM(REG_HVCONTROL2, _BIT6, _MASK1),
HVCONTROL2_MTxBusRes = REG_ITEM(REG_HVCONTROL2, _BIT5, _MASK1),
HVCONTROL2_MTxEn = REG_ITEM(REG_HVCONTROL2, _BIT4, _MASK1),
HVCONTROL2_MPing = REG_ITEM(REG_HVCONTROL2, _BIT3, _MASK1),
HVCONTROL2_DP06En = REG_ITEM(REG_HVCONTROL2, _BIT1, _MASK1),
HVCONTROL2_HVDigEn = REG_ITEM(REG_HVCONTROL2, _BIT0, _MASK1),
};
/* For adcmode
struct reg_value_set {
int value;
char *alias;
};
*/
/*
* Path Switching (Control1)
* D+ [5:3] / D- [2:0]
* 000: Open all / 001: USB / 010: AUDIO / 011: UART / 100 : USB_CP / 101 : UART_CP
*/
enum {
_ID_OPEN = 0x0,
_ID_BYPASS = 0x1,
_NO_BC_COMP_OFF = 0x0,
_NO_BC_COMP_ON = 0x1,
_D_OPEN = 0x0,
_D_USB = 0x1,
_D_AUDIO = 0x2,
_D_UART = 0x3,
_D_USB_CP = 0x4,
_D_UART_CP = 0x5,
};
/* COM patch Values */
#define COM_VALUE(dm, open, comp_onoff) ((dm<<3)|(dm<<0)|(open<<6)| \
(comp_onoff<<7))
#define _COM_OPEN COM_VALUE(_D_OPEN, _ID_OPEN, _NO_BC_COMP_ON)
#define _COM_OPEN_WITH_V_BUS _COM_OPEN
#define _COM_UART_AP COM_VALUE(_D_UART, _ID_OPEN, _NO_BC_COMP_ON)
#define _COM_UART_CP COM_VALUE(_D_UART_CP, _ID_OPEN, _NO_BC_COMP_ON)
#define _COM_USB_CP COM_VALUE(_D_USB_CP, _ID_OPEN, _NO_BC_COMP_ON)
#define _COM_USB_AP COM_VALUE(_D_USB, _ID_OPEN, _NO_BC_COMP_ON)
#define _COM_AUDIO COM_VALUE(_D_AUDIO, _ID_OPEN, _NO_BC_COMP_OFF)
static int max77865_com_value_tbl[] = {
[COM_OPEN] = _COM_OPEN,
[COM_OPEN_WITH_V_BUS] = _COM_OPEN_WITH_V_BUS,
[COM_UART_AP] = _COM_UART_AP,
[COM_UART_CP] = _COM_UART_CP,
[COM_USB_AP] = _COM_USB_AP,
[COM_USB_CP] = _COM_USB_CP,
[COM_AUDIO] = _COM_AUDIO,
};
static regmap_t max77865_muic_regmap_table[] = {
[REG_ID] = {"ID", 0x65, 0x00, INIT_NONE},
[REG_INT_MAIN] = {"INT_MAIN", 0x00, 0x00, INIT_INT_CLR,},
[REG_INT_BC] = {"INT_BC", 0x00, 0x00, INIT_INT_CLR,},
[REG_INT_FC] = {"INT_FC", 0x00, 0x00, INIT_INT_CLR,},
[REG_INT_GP] = {"INT_GP", 0x00, 0x00, INIT_INT_CLR,},
[REG_INTMASK_MAIN] = {"INTMASK_MAIN", 0x0F, 0x00, INIT_NONE,},
[REG_INTMASK_BC] = {"INTMASK_BC", 0xFF, 0x00, INIT_NONE,},
[REG_INTMASK_FC] = {"INTMASK_FC", 0xFF, 0x00, INIT_NONE,},
[REG_INTMASK_GP] = {"INTMASK_GP", 0xFD, 0x00, INIT_NONE,},
[REG_STATUS1_BC] = {"STATUS1_BC", 0x00, 0x00, INIT_NONE,},
[REG_STATUS2_BC] = {"STATUS2_BC", 0x00, 0x00, INIT_NONE,},
[REG_STATUS_GP] = {"STATUS_GP", 0xE0, 0x00, INIT_NONE,},
[REG_CONTROL1_BC] = {"CONTROL1_BC", 0xC5, 0x00, INIT_NONE,},
[REG_CONTROL2_BC] = {"CONTROL2_BC", 0x00, 0x00, INIT_NONE,},
[REG_CCDET] = {"CCDET", 0x00, 0x00, INIT_CCDET,},
[REG_CONTROL1] = {"CONTROL1", 0x00, 0x00, INIT_NONE,},
#if defined(CONFIG_SEC_FACTORY)
[REG_CONTROL2] = {"CONTROL2", 0x00, 0x00, INIT_NONE,},
#else
[REG_CONTROL2] = {"CONTROL2", 0x00, 0x00, INIT_CONTROL2,},
#endif
[REG_CONTROL3] = {"CONTROL3", 0x20, 0x00, INIT_NONE,},
[REG_CONTROL4] = {"CONTROL4", 0x30, 0x00, INIT_CONTROL4,},
[REG_HVCONTROL1] = {"HVCONTROL1", 0x00, 0x00, INIT_NONE,},
[REG_HVCONTROL2] = {"HVCONTROL2", 0x00, 0x00, INIT_NONE,},
[REG_END] = {NULL, 0, 0, INIT_NONE},
};
static int max77865_muic_ioctl(struct regmap_desc *pdesc,
int arg1, int *arg2, int *arg3)
{
int ret = 0;
switch (arg1) {
case GET_COM_VAL:
*arg2 = max77865_com_value_tbl[*arg2];
*arg3 = REG_CONTROL1;
break;
case GET_ADC:
*arg3 = STATUS_GP_UID;
break;
case GET_REVISION:
*arg3 = ID_CHIP_REV;
break;
case GET_OTG_STATUS:
*arg3 = INTMASK_BC_VBVolt;
break;
case GET_CHGTYPE:
*arg3 = STATUS1_BC_ChgTyp;
break;
case GET_PRCHGTYPE:
*arg3 = STATUS1_BC_PrChgTyp;
break;
default:
ret = -1;
break;
}
if (pdesc->trace) {
pr_info("%s: ret:%d arg1:%x,", __func__, ret, arg1);
if (arg2)
pr_info(" arg2:%x,", *arg2);
if (arg3)
pr_info(" arg3:%x - %s", *arg3,
regmap_to_name(pdesc, _ATTR_ADDR(*arg3)));
pr_info("\n");
}
return ret;
}
static int max77865_attach_ta(struct regmap_desc *pdesc)
{
int attr, value, ret;
pr_info("%s\n", __func__);
attr = REG_CONTROL1;
value = _COM_OPEN;
ret = regmap_write_value(pdesc, attr, value);
if (ret < 0)
pr_err("%s CNTR1 reg write fail.\n", __func__);
else
_REGMAP_TRACE(pdesc, 'w', ret, attr, value);
return ret;
}
static int max77865_detach_ta(struct regmap_desc *pdesc)
{
int attr, value, ret;
pr_info("%s\n", __func__);
attr = REG_CONTROL1 | _ATTR_OVERWRITE_M;
value = _COM_OPEN;
ret = regmap_write_value(pdesc, attr, value);
if (ret < 0)
pr_err("%s CNTR1 reg write fail.\n", __func__);
else
_REGMAP_TRACE(pdesc, 'w', ret, attr, value);
return ret;
}
static int max77865_set_rustproof(struct regmap_desc *pdesc, int op)
{
pr_info("%s: Not implemented.\n", __func__);
return 0;
}
static int max77865_get_vps_data(struct regmap_desc *pdesc, void *pbuf)
{
vps_data_t *pvps = (vps_data_t *)pbuf;
int attr;
attr = REG_ITEM(REG_STATUS1_BC, _BIT0, _MASK8);
*(u8 *)&pvps->t.status[0] = regmap_read_value(pdesc, attr + 0); /* BC STATUS1 */
*(u8 *)&pvps->t.status[1] = regmap_read_value(pdesc, attr + 1); /* BC STATUS2 */
*(u8 *)&pvps->t.status[2] = regmap_read_value(pdesc, attr + 2); /* GP STATUS */
attr = REG_ITEM(REG_CONTROL1_BC, _BIT0, _MASK8);
*(u8 *)&pvps->t.bccontrol[0] = regmap_read_value(pdesc, attr + 0);
*(u8 *)&pvps->t.bccontrol[1] = regmap_read_value(pdesc, attr + 1);
attr = REG_ITEM(REG_CONTROL1, _BIT0, _MASK8);
*(u8 *)&pvps->t.control[0] = regmap_read_value(pdesc, attr + 0);
*(u8 *)&pvps->t.control[1] = regmap_read_value(pdesc, attr + 1);
*(u8 *)&pvps->t.control[2] = regmap_read_value(pdesc, attr + 2);
*(u8 *)&pvps->t.control[3] = regmap_read_value(pdesc, attr + 3);
attr = REG_ITEM(REG_HVCONTROL1, _BIT0, _MASK8);
*(u8 *)&pvps->t.hvcontrol[0] = regmap_read_value(pdesc, attr + 0);
*(u8 *)&pvps->t.hvcontrol[1] = regmap_read_value(pdesc, attr + 1);
attr = STATUS_GP_UID;
*(u8 *)&pvps->t.uid = (pvps->t.status[2] >> _ATTR_BITP(attr)) & _ATTR_MASK(attr);
switch(pvps->t.uid) {
case 0: /* 301Kohm */
pvps->t.adc = 0x19;
break;
case 1: /* 523Kohm */
pvps->t.adc = 0x1c;
break;
case 2: /* RSVD */
break;
case 3: /* OPEN */
pvps->t.adc = 0x1f;
break;
default:
break;
}
attr = STATUS_GP_UIDGND;
*(u8 *)&pvps->t.uidgnd = (pvps->t.status[2] >> _ATTR_BITP(attr)) & _ATTR_MASK(attr);
attr = STATUS1_BC_VBVolt;
*(u8 *)&pvps->t.vbvolt = (pvps->t.status[0] >> _ATTR_BITP(attr)) & _ATTR_MASK(attr);
attr = STATUS1_BC_ChgDetRun;
*(u8 *)&pvps->t.chgdetrun = (pvps->t.status[0] >> _ATTR_BITP(attr)) & _ATTR_MASK(attr);
attr = STATUS1_BC_ChgTyp;
*(u8 *)&pvps->t.chgtyp = (pvps->t.status[0] >> _ATTR_BITP(attr)) & _ATTR_MASK(attr);
attr = STATUS1_BC_PrChgTyp;
*(u8 *)&pvps->t.prchgtyp = (pvps->t.status[0] >> _ATTR_BITP(attr)) & _ATTR_MASK(attr);
/* 1: timedout, 0: Not yet expired */
attr = STATUS1_BC_DCDTmr;
*(u8 *)&pvps->t.DCDTimedout = (pvps->t.status[0] >> _ATTR_BITP(attr)) & _ATTR_MASK(attr);
return 0;
}
static int max77865_enable_accdet(struct regmap_desc *pdesc, int enable)
{
pr_info("%s: %s\n", __func__, enable ? "Enable": "Disable");
pr_info("%s: Not USE\n", __func__);
return 0;
}
static int max77865_enable_chgdet(struct regmap_desc *pdesc, int enable)
{
int attr, value, ret;
pr_info("%s: %s\n", __func__, enable ? "Enable": "Disable");
attr = CONTROL1_BC_ChgDetEn;
value = enable ? 1: 0; /* 1: enable, 0: disable */
ret = regmap_write_value(pdesc, attr, value);
if (ret < 0)
pr_err("%s CNTR1 reg write fail.\n", __func__);
else
_REGMAP_TRACE(pdesc, 'w', ret, attr, value);
return ret;
}
#define BC_CONTROL1_CHGDETMAN_SHIFT 1
#define BC_CONTROL1_CHGDETMAN_MASK (0x1 << BC_CONTROL1_CHGDETMAN_SHIFT)
static int max77865_run_chgdet(struct regmap_desc *pdesc, bool started)
{
int value, ret, rvalue, wvalue;
pr_info("%s: %s\n", __func__, started ? "started": "disabled");
value = started ? 1 : 0; /* 0: Disabled, 1: Force a Manual Charger Detection */
rvalue = muic_i2c_read_byte(pdesc->muic->i2c, REG_CONTROL1_BC);
if (value)
wvalue = rvalue | BC_CONTROL1_CHGDETMAN_MASK;
else
wvalue = rvalue & (~BC_CONTROL1_CHGDETMAN_MASK);
ret = muic_i2c_write_byte(pdesc->muic->i2c, REG_CONTROL1_BC, wvalue);
if (ret < 0)
pr_err("%s CNTR1 reg write fail.\n", __func__);
else
pr_info("%s: 0x%02x -> 0x%02x\n", __func__, rvalue, wvalue);
return ret;
}
static int max77865_start_otg_test(struct regmap_desc *pdesc, int started)
{
pr_info("%s: %s\n", __func__, started ? "started": "stopped");
if (started) {
max77865_enable_chgdet(pdesc, 0);
max77865_enable_accdet(pdesc, 1);
} else
max77865_enable_chgdet(pdesc, 1);
return 0;
}
static int max77865_get_adc_scan_mode(struct regmap_desc *pdesc)
{
pr_info("%s: Not USE\n", __func__);
return 0;
}
static void max77865_set_adc_scan_mode(struct regmap_desc *pdesc,
const int mode)
{
pr_info("%s: Not USE\n", __func__);
}
enum switching_mode_val{
_SWMODE_AUTO = 0,
_SWMODE_MANUAL = 1,
};
static int max77865_get_switching_mode(struct regmap_desc *pdesc)
{
return SWMODE_AUTO;
}
static void max77865_set_switching_mode(struct regmap_desc *pdesc, int mode)
{
int attr, value;
int ret = 0;
pr_info("%s\n",__func__);
value = (mode == SWMODE_AUTO) ? _SWMODE_AUTO : _SWMODE_MANUAL;
attr = CONTROL1_NoBCComp;
ret = regmap_write_value(pdesc, attr, value);
if (ret < 0)
pr_err("%s REG_CTRL write fail.\n", __func__);
else
_REGMAP_TRACE(pdesc, 'w', ret, attr, value);
}
#if defined(CONFIG_MUIC_TEST_FUNC)
static int max77854_usb_to_ta(struct regmap_desc *pdesc, int mode)
{
int ret = -1;
muic_data_t *pmuic = pdesc->muic;
vps_data_t *pmsr = &pmuic->vps;
pr_info("%s\n",__func__);
if (mode == 0) {
pr_info("%s, Disable USB to TA\n",__func__);
if (pmuic->attached_dev == ATTACHED_DEV_TA_MUIC && pmuic->usb_to_ta_state) {
switch (pmsr->t.chgtyp) {
case 1:
pmuic->attached_dev = ATTACHED_DEV_USB_MUIC;
break;
case 2:
pmuic->attached_dev =ATTACHED_DEV_CDP_MUIC;
break;
}
muic_notifier_detach_attached_dev(ATTACHED_DEV_TA_MUIC);
muic_notifier_attach_attached_dev(pmuic->attached_dev);
pmuic->usb_to_ta_state = false;
}
} else if (mode == 1) {
pr_info("%s, Enable USB to TA\n",__func__);
if ((pdesc->muic->attached_dev == ATTACHED_DEV_CDP_MUIC ||
pdesc->muic->attached_dev == ATTACHED_DEV_USB_MUIC)
&& !pmuic->usb_to_ta_state) {
muic_notifier_detach_attached_dev(pdesc->muic->attached_dev);
muic_notifier_attach_attached_dev(ATTACHED_DEV_TA_MUIC);
pmuic->attached_dev = ATTACHED_DEV_TA_MUIC;
pmuic->usb_to_ta_state = true;
}
} else if (mode == 2) {
pr_info("%s, USB to TA %s\n",__func__,
pmuic->usb_to_ta_state?"Enabled":"Disabled");
ret = pmuic->usb_to_ta_state;
} else {
pr_info("%s, Unknown CMD\n",__func__);
}
return ret;
}
#endif
static int max77865_get_vbus_value(struct regmap_desc *pdesc)
{
muic_data_t *muic = pdesc->muic;
int vbadc, result = 0;
int adcen;
pr_info("%s\n",__func__);
adcen = i2c_smbus_read_byte_data(muic->i2c, REG_HVCONTROL1);
i2c_smbus_write_byte_data(muic->i2c, REG_HVCONTROL1, adcen | 0x01);
msleep(100);
vbadc = regmap_read_value(pdesc, STATUS_GP_VbADC);
switch (vbadc) {
case 0:
result = 0;
break;
case 1:
case 2:
case 3:
result = 5;
break;
case 4:
result = vbadc+3;
break;
case 5:
case 6:
result = 9;
break;
case 7:
case 8:
case 9:
result = 12;
break;
case (10)...(15):
result = vbadc+4;
break;
default:
break;
}
i2c_smbus_write_byte_data(muic->i2c, REG_HVCONTROL1, adcen);
return result;
}
static void max77865_get_fromatted_dump(struct regmap_desc *pdesc, char *mesg)
{
muic_data_t *muic = pdesc->muic;
int val;
if (pdesc->trace)
pr_info("%s\n", __func__);
val = i2c_smbus_read_byte_data(muic->i2c, REG_STATUS1_BC);
sprintf(mesg+strlen(mesg), "ST1_BC:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_STATUS2_BC);
sprintf(mesg+strlen(mesg), "ST2_BC:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_STATUS_GP);
sprintf(mesg+strlen(mesg), "ST_GP:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_INTMASK_MAIN);
sprintf(mesg+strlen(mesg), "IM_MAIN:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_INTMASK_BC);
sprintf(mesg+strlen(mesg), "IM_BC:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_INTMASK_FC);
sprintf(mesg+strlen(mesg), "IM_FC:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_INTMASK_GP);
sprintf(mesg+strlen(mesg), "IM_GP:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_CONTROL1_BC);
sprintf(mesg+strlen(mesg), "CT1_BC:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_CONTROL2_BC);
sprintf(mesg+strlen(mesg), "CT2_BC:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_CONTROL1);
sprintf(mesg+strlen(mesg), "CT1:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_CONTROL2);
sprintf(mesg+strlen(mesg), "CT2:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_CONTROL3);
sprintf(mesg+strlen(mesg), "CT3:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_CONTROL4);
sprintf(mesg+strlen(mesg), "CT4:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_HVCONTROL1);
sprintf(mesg+strlen(mesg), "HV1:%x ", val);
val = i2c_smbus_read_byte_data(muic->i2c, REG_HVCONTROL2);
sprintf(mesg+strlen(mesg), "HV2:%x ", val);
}
static int max77865_get_sizeof_regmap(void)
{
pr_info("%s:%s\n", MUIC_DEV_NAME, __func__);
return (int)ARRAY_SIZE(max77865_muic_regmap_table);
}
/* Need to implement */
void _max77865_muic_read_register(struct i2c_client *i2c)
{
pr_info("%s: Not implemented.\n", __func__);
}
int max77865_muic_read_register(struct i2c_client *i2c)
__attribute__((weak, alias("_max77865_muic_read_register")));
static int max77865_init_reg_func(struct regmap_desc *pdesc)
{
pr_info("%s\n", __func__);
return 0;
}
static struct regmap_ops max77865_muic_regmap_ops = {
.get_size = max77865_get_sizeof_regmap,
.ioctl = max77865_muic_ioctl,
.get_formatted_dump = max77865_get_fromatted_dump,
.init = max77865_init_reg_func,
};
static struct vendor_ops max77865_muic_vendor_ops = {
.attach_ta = max77865_attach_ta,
.detach_ta = max77865_detach_ta,
.get_switch = max77865_get_switching_mode,
.set_switch = max77865_set_switching_mode,
.set_adc_scan_mode = max77865_set_adc_scan_mode,
.get_adc_scan_mode = max77865_get_adc_scan_mode,
.set_rustproof = max77865_set_rustproof,
.enable_accdet = max77865_enable_accdet,
.enable_chgdet = max77865_enable_chgdet,
.run_chgdet = max77865_run_chgdet,
.start_otg_test = max77865_start_otg_test,
.get_vps_data = max77865_get_vps_data,
.get_vbus_value = max77865_get_vbus_value,
#if defined(CONFIG_MUIC_TEST_FUNC)
.usb_to_ta = max77854_usb_to_ta,
#endif
};
static struct regmap_desc max77865_muic_regmap_desc = {
.name = "max77865-MUIC",
.regmap = max77865_muic_regmap_table,
.size = REG_END,
.regmapops = &max77865_muic_regmap_ops,
.vendorops = &max77865_muic_vendor_ops,
};
void muic_register_max77865_regmap_desc(struct regmap_desc **pdesc)
{
*pdesc = &max77865_muic_regmap_desc;
}