/* * muic_apis.c * * Copyright (C) 2014 Samsung Electronics * Thomas Ryu * * 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 #include #include #include #include #include #include #include #include #include #if defined(CONFIG_MUIC_NOTIFIER) #include #endif /* CONFIG_MUIC_NOTIFIER */ #if defined (CONFIG_OF) #include #include #endif /* CONFIG_OF */ #include "muic-internal.h" #include "muic_i2c.h" #include "muic_regmap.h" int attach_ta(muic_data_t *pmuic) { struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; if (pvendor->attach_ta) { pr_info("%s: ", __func__); pvendor->attach_ta(pmuic->regmapdesc); } else pr_info("%s: No Vendor API ready.\n", __func__); return 0; } int detach_ta(muic_data_t *pmuic) { struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; if (pvendor->detach_ta) { pr_info("%s: ", __func__); pvendor->detach_ta(pmuic->regmapdesc); } else pr_info("%s: No Vendor API ready.\n", __func__); return 0; } static int get_charger_type(muic_data_t *pmuic) { struct regmap_ops *pops = pmuic->regmapdesc->regmapops; int uattr; pops->ioctl(pmuic->regmapdesc, GET_CHGTYPE, NULL, &uattr); return regmap_read_value(pmuic->regmapdesc, uattr); } static int set_BCD_RESCAN_reg(muic_data_t *pmuic, int value) { struct regmap_ops *pops = pmuic->regmapdesc->regmapops; struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; int uattr, ret; if (pvendor && pvendor->rescan) { ret = pvendor->rescan(pmuic->regmapdesc, value); return ret; } pops->ioctl(pmuic->regmapdesc, GET_RESID3, NULL, &uattr); #if defined(CONFIG_MUIC_UNIVERSAL_SM5504) value = !value; #else uattr |= _ATTR_OVERWRITE_M; #endif ret = regmap_write_value(pmuic->regmapdesc, uattr, value); _REGMAP_TRACE(pmuic->regmapdesc, 'w', ret, uattr, value); return ret; } int do_BCD_rescan(muic_data_t *pmuic) { static int bcd_rescan = 0; pr_info("%s\n", __func__); if (bcd_rescan) { int chg_type = get_charger_type(pmuic); int new_dev = 0; bcd_rescan = 0; if (chg_type < 0) pr_err("%s:%s err %d\n", MUIC_DEV_NAME, __func__, chg_type); pr_info("%s [MUIC] BCD result chg_type = 0x%x \n", __func__, chg_type); switch(chg_type) { case 0x01 : // DCP new_dev = ATTACHED_DEV_TA_MUIC; break; case 0x02 : // CDP new_dev = ATTACHED_DEV_CDP_MUIC; break; case 0x04 : // SDP new_dev = ATTACHED_DEV_USB_MUIC; break; case 0x08 : // Time out SDP new_dev = ATTACHED_DEV_USB_MUIC; break; case 0x10 : // U200 new_dev = ATTACHED_DEV_TA_MUIC; break; } return new_dev; } pr_info("[MUIC] 219K USB Cable/Charger Connected\n"); pr_info("[MUIC] BCD rescan\n"); // 0x21 -> 1 0x21 -> 0 set_BCD_RESCAN_reg(pmuic, 0x01); msleep(1); pr_info("[MUIC] Writing BCD_RECAN\n"); set_BCD_RESCAN_reg(pmuic, 0x00); bcd_rescan = 1; return 0; } int get_switch_mode(muic_data_t *pmuic) { struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; int val=0; if (pvendor->get_switch) { pr_info("%s: ", __func__); val = pvendor->get_switch(pmuic->regmapdesc); } else{ pr_info("%s: No Vendor API ready.\n", __func__); val = -1; } return val; } void set_switch_mode(muic_data_t *pmuic, int mode) { struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; if (pvendor->set_switch) { pr_info("%s: ", __func__); pvendor->set_switch(pmuic->regmapdesc,mode); } else{ pr_info("%s: No Vendor API ready.\n", __func__); } return; } int get_adc_scan_mode(muic_data_t *pmuic) { struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; int value = 0; if (pvendor->get_adc_scan_mode) { pr_info("%s: ", __func__); value = pvendor->get_adc_scan_mode(pmuic->regmapdesc); } else{ pr_info("%s: No Vendor API ready.\n", __func__); value = -1; } return value; } void set_adc_scan_mode(muic_data_t *pmuic, const u8 val) { struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; if (pvendor->set_adc_scan_mode) { pr_info("%s: ", __func__); pvendor->set_adc_scan_mode(pmuic->regmapdesc,val); } else pr_info("%s: No Vendor API ready.\n", __func__); return; } #define com_to_open com_to_open_with_vbus #ifndef com_to_open int com_to_open(muic_data_t *pmuic) { int ret = 0; ret = regmap_com_to(pmuic->regmapdesc, COM_OPEN); if (ret < 0) pr_err("%s:%s com_to_open err\n", MUIC_DEV_NAME, __func__); return ret; } #endif int com_to_open_with_vbus(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = regmap_com_to(pmuic->regmapdesc, COM_OPEN_WITH_V_BUS); if (ret < 0) pr_err("%s:%s com_to_open err\n", MUIC_DEV_NAME, __func__); return ret; } int com_to_usb_ap(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = regmap_com_to(pmuic->regmapdesc, COM_USB_AP); if (ret < 0) pr_err("%s:%s set_com_usb err\n", MUIC_DEV_NAME, __func__); return ret; } int com_to_usb_cp(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = regmap_com_to(pmuic->regmapdesc, COM_USB_CP); if (ret < 0) pr_err("%s:%s set_com_usb err\n", MUIC_DEV_NAME, __func__); return ret; } static int set_rustproof_mode(struct regmap_desc *pdesc, int op) { struct vendor_ops *pvendor = pdesc->vendorops; if (pvendor->set_rustproof) { pr_info("%s: %s", __func__, op ? "On" : "Off"); pvendor->set_rustproof(pdesc, op); } else pr_err("%s: No Vendor API ready.\n", __func__); return 0; } int com_to_uart_ap(muic_data_t *pmuic) { int com_index = 0, ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); com_index = pmuic->is_rustproof ? COM_OPEN_WITH_V_BUS : COM_UART_AP; ret = regmap_com_to(pmuic->regmapdesc, com_index); if (ret < 0) pr_err("%s:%s set_com_uart err\n", MUIC_DEV_NAME, __func__); if(pmuic->is_rustproof) { pr_info("%s:%s rustproof mode Enabled\n", MUIC_DEV_NAME, __func__); set_rustproof_mode(pmuic->regmapdesc, 1); } return ret; } int com_to_uart_cp(muic_data_t *pmuic) { int com_index = 0, ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); com_index = pmuic->is_rustproof ? COM_OPEN_WITH_V_BUS : COM_UART_CP; ret = regmap_com_to(pmuic->regmapdesc, com_index); if (ret < 0) pr_err("%s:%s set_com_uart err\n", MUIC_DEV_NAME, __func__); if(pmuic->is_rustproof) { pr_info("%s:%s rustproof mode Enabled\n", MUIC_DEV_NAME, __func__); set_rustproof_mode(pmuic->regmapdesc, 1); } return ret; } int com_to_audio(muic_data_t *pmuic) { int ret = 0; ret = regmap_com_to(pmuic->regmapdesc, COM_AUDIO); if (ret < 0) pr_err("%s:%s set_com_audio err\n", MUIC_DEV_NAME, __func__); return ret; } int switch_to_ap_usb(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = com_to_usb_ap(pmuic); if (ret < 0) { pr_err("%s:%s com->usb set err\n", MUIC_DEV_NAME, __func__); return ret; } return ret; } int switch_to_cp_usb(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = com_to_usb_cp(pmuic); if (ret < 0) { pr_err("%s:%s com->usb set err\n", MUIC_DEV_NAME, __func__); return ret; } return ret; } int switch_to_ap_uart(muic_data_t *pmuic) { struct muic_platform_data *pdata = pmuic->pdata; int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); if (pdata->set_gpio_uart_sel) pdata->set_gpio_uart_sel(MUIC_PATH_UART_AP); ret = com_to_uart_ap(pmuic); if (ret < 0) { pr_err("%s:%s com->uart set err\n", MUIC_DEV_NAME, __func__); return ret; } return ret; } int switch_to_cp_uart(muic_data_t *pmuic) { struct muic_platform_data *pdata = pmuic->pdata; int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); if (pdata->set_gpio_uart_sel) pdata->set_gpio_uart_sel(MUIC_PATH_UART_CP); ret = com_to_uart_cp(pmuic); if (ret < 0) { pr_err("%s:%s com->uart set err\n", MUIC_DEV_NAME, __func__); return ret; } return ret; } int attach_uart_util(muic_data_t *pmuic, muic_attached_dev_t new_dev) { int ret = 0; pmuic->attached_dev = new_dev; if (pmuic->pdata->usb_path == MUIC_PATH_UART_AP) { ret = switch_to_ap_uart(pmuic); } else if (pmuic->pdata->usb_path == MUIC_PATH_UART_CP) { ret = switch_to_cp_uart(pmuic); } else pr_warn("%s:%s invalid usb_path\n", MUIC_DEV_NAME, __func__); return ret; } int attach_usb_util(muic_data_t *pmuic, muic_attached_dev_t new_dev) { int ret = 0; pmuic->attached_dev = new_dev; if (pmuic->pdata->usb_path == MUIC_PATH_USB_AP) { ret = switch_to_ap_usb(pmuic); } else if (pmuic->pdata->usb_path == MUIC_PATH_USB_CP) { ret = switch_to_cp_usb(pmuic); } else pr_warn("%s:%s invalid usb_path\n", MUIC_DEV_NAME, __func__); return ret; } int attach_usb(muic_data_t *pmuic, muic_attached_dev_t new_dev) { int ret = 0; if (pmuic->attached_dev == new_dev) { pr_info("%s:%s duplicated(USB)\n", MUIC_DEV_NAME, __func__); return ret; } pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = attach_usb_util(pmuic, new_dev); if (ret < 0) { pr_err("%s:%s fail.(%d)\n", MUIC_DEV_NAME, __func__, ret); return ret; } return ret; } int detach_usb(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s attached_dev type(%d)\n", MUIC_DEV_NAME, __func__, pmuic->attached_dev); ret = com_to_open_with_vbus(pmuic); if (ret < 0) { pr_err("%s:%s fail.(%d)\n", MUIC_DEV_NAME, __func__, ret); return ret; } pmuic->attached_dev = ATTACHED_DEV_NONE_MUIC; return ret; } int attach_otg_usb(muic_data_t *pmuic, muic_attached_dev_t new_dev) { int ret = 0; if (pmuic->attached_dev == new_dev) { pr_info("%s:%s duplicated(USB)\n", MUIC_DEV_NAME, __func__); return ret; } pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); /* LANHUB doesn't work under AUTO switch mode, so turn it off */ /* set MANUAL SW mode */ set_switch_mode(pmuic,SWMODE_MANUAL); /* enable RAW DATA mode, only for OTG LANHUB */ set_adc_scan_mode(pmuic,ADC_SCANMODE_CONTINUOUS); ret = switch_to_ap_usb(pmuic); pmuic->attached_dev = new_dev; return ret; } int detach_otg_usb(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s attached_dev type(%d)\n", MUIC_DEV_NAME, __func__, pmuic->attached_dev); ret = com_to_open_with_vbus(pmuic); if (ret < 0) { pr_err("%s:%s fail.(%d)\n", MUIC_DEV_NAME, __func__, ret); return ret; } /* disable RAW DATA mode */ set_adc_scan_mode(pmuic,ADC_SCANMODE_ONESHOT); /* set AUTO SW mode */ set_switch_mode(pmuic,SWMODE_AUTO); pmuic->attached_dev = ATTACHED_DEV_NONE_MUIC; return ret; } int attach_ps_cable(muic_data_t *pmuic, muic_attached_dev_t new_dev) { int ret = 0; pr_info("%s:%s new_dev(%d)\n", MUIC_DEV_NAME, __func__, new_dev); com_to_open_with_vbus(pmuic); pmuic->attached_dev = new_dev; return ret; } int detach_ps_cable(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); pmuic->attached_dev = ATTACHED_DEV_NONE_MUIC; return ret; } int attach_deskdock(muic_data_t *pmuic, muic_attached_dev_t new_dev) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); /* Audio-out doesn't work under AUTO switch mode, so turn it off */ /* set MANUAL SW mode */ set_switch_mode(pmuic,SWMODE_MANUAL); ret = com_to_audio(pmuic); if (ret < 0) { pr_err("%s:%s fail.(%d)\n", MUIC_DEV_NAME, __func__, ret); return ret; } pmuic->attached_dev = new_dev; return ret; } int detach_deskdock(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); set_switch_mode(pmuic,SWMODE_AUTO); pmuic->attached_dev = ATTACHED_DEV_NONE_MUIC; return ret; } int attach_audiodock(muic_data_t *pmuic, muic_attached_dev_t new_dev, u8 vbus) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = attach_usb_util(pmuic, new_dev); if (ret < 0) pr_err("%s:%s fail.(%d)\n", MUIC_DEV_NAME, __func__, ret); return ret; } int detach_audiodock(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = com_to_open_with_vbus(pmuic); if (ret < 0) return ret; pmuic->attached_dev = ATTACHED_DEV_NONE_MUIC; return ret; } int attach_jig_uart_boot_off(muic_data_t *pmuic, muic_attached_dev_t new_dev, u8 vbvolt) { struct muic_platform_data *pdata = pmuic->pdata; struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; int ret = 0; pr_info("%s:%s JIG UART BOOT-OFF(0x%x)\n", MUIC_DEV_NAME, __func__, vbvolt); if (pdata->uart_path == MUIC_PATH_UART_AP) ret = switch_to_ap_uart(pmuic); else ret = switch_to_cp_uart(pmuic); if (pvendor && pvendor->set_manual_JIGON) pvendor->set_manual_JIGON(pmuic->regmapdesc, 1); /* if VBUS is enabled, call host_notify_cb to check if it is OTGTEST*/ if (vbvolt) { if (pmuic->is_otg_test) { pr_info("%s:%s OTG_TEST\n", MUIC_DEV_NAME, __func__); /* in OTG_TEST mode, do not charge */ // new_dev = ATTACHED_DEV_JIG_UART_OFF_VB_OTG_MUIC; new_dev = ATTACHED_DEV_JIG_UART_OFF_MUIC; } else /* JIG_UART_OFF_VB */ new_dev = ATTACHED_DEV_JIG_UART_OFF_VB_MUIC; } else new_dev = ATTACHED_DEV_JIG_UART_OFF_MUIC; pmuic->attached_dev = new_dev; return new_dev; } int detach_jig_uart_boot_off(muic_data_t *pmuic) { struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); if (pvendor && pvendor->set_manual_JIGON) pvendor->set_manual_JIGON(pmuic->regmapdesc, 0); if(pmuic->is_rustproof) { pr_info("%s:%s rustproof mode : Set Auto SW mode\n", MUIC_DEV_NAME, __func__); set_rustproof_mode(pmuic->regmapdesc, 0); } pmuic->attached_dev = ATTACHED_DEV_NONE_MUIC; return ret; } /* * QA's requirement on JIG_UART_ON(619K) * 1. Factory Test Mode * Send a deskdock Noti. to wakeup the device. * (OPEN->619K->OPEN->523K ) * 2. Normal * Do not charge the device. (No charging Icon and current) * Need to set the path OPEN and cut off VBUS input. */ int attach_jig_uart_boot_on(muic_data_t *pmuic, muic_attached_dev_t new_dev) { int com_index = COM_OPEN; int ret = 0; pr_info("%s:%s JIG UART BOOT-ON(0x%x)\n", MUIC_DEV_NAME, __func__, new_dev); ret = regmap_com_to(pmuic->regmapdesc, com_index); if (ret < 0) pr_err("%s:%s set_com_uart err\n", MUIC_DEV_NAME, __func__); pr_info("%s:%s rustproof mode is set.\n", MUIC_DEV_NAME, __func__); set_rustproof_mode(pmuic->regmapdesc, 1); pmuic->attached_dev = new_dev; return ret; } int detach_jig_uart_boot_on(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s rustproof mode is restored.\n", MUIC_DEV_NAME, __func__); set_rustproof_mode(pmuic->regmapdesc, 0); pmuic->attached_dev = ATTACHED_DEV_NONE_MUIC; return ret; } int attach_jig_usb_boot_off(muic_data_t *pmuic, u8 vbvolt) { int ret = 0; if (pmuic->attached_dev == ATTACHED_DEV_JIG_USB_OFF_MUIC) { pr_info("%s:%s duplicated(JIG USB OFF)\n", MUIC_DEV_NAME, __func__); return ret; } pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = attach_usb_util(pmuic, ATTACHED_DEV_JIG_USB_OFF_MUIC); if (ret < 0) { pr_err("%s:%s fail.(%d)\n", MUIC_DEV_NAME, __func__, ret); return ret; } return ret; } int attach_jig_usb_boot_on(muic_data_t *pmuic, u8 vbvolt) { int ret = 0; if (pmuic->attached_dev == ATTACHED_DEV_JIG_USB_ON_MUIC) { pr_info("%s:%s duplicated(JIG USB ON)\n", MUIC_DEV_NAME, __func__); return ret; } pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = attach_usb_util(pmuic, ATTACHED_DEV_JIG_USB_ON_MUIC); if (ret < 0) return ret; return ret; } int attach_mhl(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); ret = com_to_open_with_vbus(pmuic); if (ret < 0) { pr_err("%s:%s fail.(%d)\n", MUIC_DEV_NAME, __func__, ret); return ret; } pmuic->attached_dev = ATTACHED_DEV_MHL_MUIC; return ret; } int detach_mhl(muic_data_t *pmuic) { int ret = 0; pr_info("%s:%s\n", MUIC_DEV_NAME, __func__); if(ret < 0) pr_err("%s:%s err detach_charger(%d)\n", MUIC_DEV_NAME, __func__, ret); pmuic->attached_dev = ATTACHED_DEV_NONE_MUIC; return ret; } int get_adc(muic_data_t *pmuic) { struct regmap_ops *pops = pmuic->regmapdesc->regmapops; int uattr; pops->ioctl(pmuic->regmapdesc, GET_ADC, NULL, &uattr); return regmap_read_value(pmuic->regmapdesc, uattr); } int get_vps_data(muic_data_t *pmuic, void *pdata) { struct vendor_ops *pvendor = pmuic->regmapdesc->vendorops; if (pvendor->get_vps_data) pvendor->get_vps_data(pmuic->regmapdesc, pdata); else pr_info("%s: No Vendor API ready.\n", __func__); return 0; } #ifdef CONFIG_UART_SEL int java_muic_set_path(void *drv_data, int path) { muic_data_t *pmuic = (muic_data_t *)drv_data; int ret = 0; pr_info("%s: %s path : %d\n", MUIC_DEV_NAME, __func__, path); if(!pmuic->is_rustproof) { if (path) { /* UART */ ret = regmap_com_to(pmuic->regmapdesc, COM_UART_AP); if (ret < 0) pr_err("%s:%s set_com_uart err\n", MUIC_DEV_NAME, __func__); set_rustproof_mode(pmuic->regmapdesc, 1); } else { /* USB */ ret = regmap_com_to(pmuic->regmapdesc, COM_USB_AP); if (ret < 0) pr_err("%s:%s set_com_usb err\n", MUIC_DEV_NAME, __func__); set_rustproof_mode(pmuic->regmapdesc, 1); } } return ret; } #endif