| /* |
| * driver/muic/s2mu004-muic_sysfs.c - S2MU004 micro USB switch device driver |
| * |
| * Copyright (C) 2015 Samsung Electronics |
| * |
| * 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 |
| * |
| */ |
| #define pr_fmt(fmt) "[MUIC] " fmt |
| |
| #include <linux/types.h> |
| #include <linux/device.h> |
| #include <linux/delay.h> |
| |
| #include <linux/mfd/samsung/s2mu004-private.h> |
| #include <linux/muic/muic.h> |
| #include <linux/muic/s2mu004-muic.h> |
| #include <linux/sec_sysfs.h> |
| #include <linux/sec_ext.h> |
| #include <linux/sec_batt.h> |
| #include "../battery_v2/include/sec_charging_common.h" |
| |
| static ssize_t s2mu004_muic_show_uart_en(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| int ret = 0; |
| |
| if (!muic_pdata->is_rustproof) { |
| pr_info("%s UART ENABLE\n", __func__); |
| ret = sprintf(buf, "1\n"); |
| } else { |
| pr_info("%s UART DISABLE\n", __func__); |
| ret = sprintf(buf, "0\n"); |
| } |
| |
| return ret; |
| } |
| |
| static ssize_t s2mu004_muic_set_uart_en(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| |
| if (!strncmp(buf, "1", 1)) |
| muic_pdata->is_rustproof = false; |
| else if (!strncmp(buf, "0", 1)) |
| muic_pdata->is_rustproof = true; |
| else |
| pr_info("%s invalid value\n", __func__); |
| |
| pr_info("%s uart_en(%d)\n", |
| __func__, !muic_pdata->is_rustproof); |
| |
| return count; |
| } |
| |
| static ssize_t s2mu004_muic_show_uart_sel(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *pdata = muic_data->pdata; |
| const char *mode = "UNKNOWN\n"; |
| |
| switch (pdata->uart_path) { |
| case MUIC_PATH_UART_AP: |
| mode = "AP\n"; |
| break; |
| case MUIC_PATH_UART_CP: |
| mode = "CP\n"; |
| break; |
| default: |
| break; |
| } |
| |
| pr_info("%s %s", __func__, mode); |
| return snprintf(buf, strlen(mode) + 1, "%s", mode); |
| } |
| |
| static ssize_t s2mu004_muic_set_uart_sel(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *pdata = muic_data->pdata; |
| struct muic_interface_t *muic_if = muic_data->if_data; |
| |
| if (!strncasecmp(buf, "AP", 2)) |
| pdata->uart_path = MUIC_PATH_UART_AP; |
| else if (!strncasecmp(buf, "CP", 2)) |
| pdata->uart_path = MUIC_PATH_UART_CP; |
| else |
| pr_warn("%s invalid value\n", __func__); |
| |
| muic_if->set_switch_to_uart(muic_data); |
| |
| pr_info("%s %s\n", __func__, buf); |
| |
| return count; |
| } |
| |
| static ssize_t s2mu004_muic_show_usb_sel(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| return sprintf(buf, "PDA\n"); |
| } |
| |
| static ssize_t s2mu004_muic_set_usb_sel(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| return count; |
| } |
| |
| static ssize_t s2mu004_muic_show_usb_en(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| |
| return sprintf(buf, "%s attached_dev = %d\n", |
| __func__, muic_pdata->attached_dev); |
| } |
| |
| static ssize_t s2mu004_muic_set_usb_en(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| muic_attached_dev_t new_dev = ATTACHED_DEV_USB_MUIC; |
| |
| if (!strncasecmp(buf, "1", 1)) |
| muic_core_handle_attach(muic_data->pdata, new_dev, 0, 0); |
| else if (!strncasecmp(buf, "0", 1)) |
| muic_core_handle_detach(muic_data->pdata); |
| else |
| pr_info("%s invalid value\n", __func__); |
| |
| pr_info("%s attached_dev(%d)\n", |
| __func__, muic_pdata->attached_dev); |
| |
| return count; |
| } |
| |
| static ssize_t s2mu004_muic_show_adc(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| #if IS_ENABLED(CONFIG_CCIC_S2MU004) |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| #endif |
| int ret; |
| |
| mutex_lock(&muic_data->muic_mutex); |
| |
| #if IS_ENABLED(CONFIG_CCIC_S2MU004) |
| /* TODO: NOTE: There are abnormal operations of rising volatage AFC 9V |
| * by RID enable/disable in the s2mu004_muic_refresh_adc functions in the |
| * factory bianary. This is to minimize unnecessary interrupt by RID |
| * enable/disable whenever reading adc sysfs node |
| */ |
| if (muic_pdata->is_factory_start && muic_pdata->attached_dev == 0) { |
| /* No cable detection means RID open */ |
| ret = ADC_OPEN; |
| } else { |
| #if IS_ENABLED(CONFIG_HV_MUIC_S2MU004_AFC) |
| if (muic_pdata->is_factory_start && muic_data->afc_check) |
| /* No need to read adc in the middle of afc detection sequences */ |
| ret = ADC_GND; |
| else |
| #endif |
| ret = s2mu004_muic_refresh_adc(muic_data); |
| } |
| #if IS_ENABLED(CONFIG_HV_MUIC_S2MU004_AFC) |
| pr_info("%s: factory: %d attached_dev: %d afc ready: %d", __func__, |
| muic_pdata->is_factory_start, muic_pdata->attached_dev, |
| muic_data->afc_check); |
| #endif |
| #else |
| ret = s2mu004_i2c_read_byte(muic_data->i2c, S2MU004_REG_MUIC_ADC); |
| #endif |
| |
| mutex_unlock(&muic_data->muic_mutex); |
| if (ret < 0) { |
| pr_err("%s err read adc reg(%d)\n", |
| __func__, ret); |
| return sprintf(buf, "UNKNOWN\n"); |
| } |
| |
| return sprintf(buf, "%x\n", (ret & ADC_MASK)); |
| } |
| |
| static ssize_t s2mu004_muic_show_usb_state(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| static unsigned long swtich_slot_time; |
| |
| if (printk_timed_ratelimit(&swtich_slot_time, 5000)) |
| pr_info("%s muic_pdata->attached_dev(%d)\n", |
| __func__, muic_pdata->attached_dev); |
| |
| switch (muic_pdata->attached_dev) { |
| case ATTACHED_DEV_USB_MUIC: |
| case ATTACHED_DEV_CDP_MUIC: |
| case ATTACHED_DEV_JIG_USB_OFF_MUIC: |
| case ATTACHED_DEV_JIG_USB_ON_MUIC: |
| return sprintf(buf, "USB_STATE_CONFIGURED\n"); |
| default: |
| break; |
| } |
| |
| return 0; |
| } |
| |
| #if IS_ENABLED(DEBUG_MUIC) |
| static ssize_t s2mu004_muic_show_mansw(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| int ret; |
| |
| mutex_lock(&muic_data->muic_mutex); |
| ret = s2mu004_i2c_read_byte(muic_data->i2c, S2MU004_REG_MUIC_SW_CTRL); |
| mutex_unlock(&muic_data->muic_mutex); |
| |
| pr_info("%s ret:%d buf%s\n", __func__, ret, buf); |
| |
| if (ret < 0) { |
| pr_err("%s: fail to read muic reg\n", __func__); |
| return sprintf(buf, "UNKNOWN\n"); |
| } |
| return sprintf(buf, "0x%x\n", ret); |
| } |
| static ssize_t s2mu004_muic_show_interrupt_status(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| int st1, st2; |
| |
| mutex_lock(&muic_data->muic_mutex); |
| st1 = s2mu004_i2c_read_byte(muic_data->i2c, S2MU004_REG_MUIC_INT1); |
| st2 = s2mu004_i2c_read_byte(muic_data->i2c, S2MU004_REG_MUIC_INT2); |
| mutex_unlock(&muic_data->muic_mutex); |
| |
| pr_info("%s st1:0x%x st2:0x%x buf%s\n", __func__, st1, st2, buf); |
| |
| if (st1 < 0 || st2 < 0) { |
| pr_err("%s: fail to read muic reg\n", __func__); |
| return sprintf(buf, "UNKNOWN\n"); |
| } |
| return sprintf(buf, "st1:0x%x st2:0x%x\n", st1, st2); |
| } |
| static ssize_t s2mu004_muic_show_registers(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| char mesg[256] = ""; |
| |
| mutex_lock(&muic_data->muic_mutex); |
| s2mu004_read_reg_dump(muic_data, mesg); |
| mutex_unlock(&muic_data->muic_mutex); |
| pr_info("%s:%s\n", __func__, mesg); |
| |
| return sprintf(buf, "%s\n", mesg); |
| } |
| #endif |
| |
| #if IS_ENABLED(CONFIG_USB_HOST_NOTIFY) |
| static ssize_t s2mu004_muic_show_otg_test(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| int ret; |
| u8 val = 0; |
| |
| mutex_lock(&muic_data->muic_mutex); |
| ret = s2mu004_i2c_read_byte(muic_data->i2c, |
| S2MU004_REG_MUIC_INT2_MASK); |
| mutex_unlock(&muic_data->muic_mutex); |
| |
| if (ret < 0) { |
| pr_err("%s: fail to read muic reg\n", __func__); |
| return sprintf(buf, "UNKNOWN\n"); |
| } |
| |
| pr_info("%s ret:%d val:%x buf%s\n", |
| __func__, ret, val, buf); |
| |
| val &= INT_VBUS_ON_MASK; |
| return sprintf(buf, "%x\n", val); |
| } |
| |
| static ssize_t s2mu004_muic_set_otg_test(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| |
| pr_info("%s buf:%s\n", __func__, buf); |
| |
| /* |
| * The otg_test is set 0 durring the otg test. Not 1 !!! |
| */ |
| |
| if (!strncmp(buf, "0", 1)) { |
| muic_pdata->is_otg_test = 1; |
| #ifdef CONFIG_SEC_FACTORY |
| s2mu004_muic_set_otg_reg(muic_data, 1); |
| #endif |
| } else if (!strncmp(buf, "1", 1)) { |
| muic_pdata->is_otg_test = 0; |
| #ifdef CONFIG_SEC_FACTORY |
| s2mu004_muic_set_otg_reg(muic_data, 0); |
| #endif |
| } else { |
| pr_info("%s Wrong command\n", __func__); |
| return count; |
| } |
| |
| return count; |
| } |
| #endif |
| |
| static ssize_t s2mu004_muic_show_attached_dev(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| int mdev = muic_pdata->attached_dev; |
| |
| pr_info("%s attached_dev:%d\n", __func__, mdev); |
| |
| switch (mdev) { |
| case ATTACHED_DEV_NONE_MUIC: |
| return sprintf(buf, "No VPS\n"); |
| case ATTACHED_DEV_USB_MUIC: |
| return sprintf(buf, "USB\n"); |
| case ATTACHED_DEV_CDP_MUIC: |
| return sprintf(buf, "CDP\n"); |
| case ATTACHED_DEV_OTG_MUIC: |
| return sprintf(buf, "OTG\n"); |
| case ATTACHED_DEV_TA_MUIC: |
| return sprintf(buf, "TA\n"); |
| case ATTACHED_DEV_JIG_UART_OFF_MUIC: |
| return sprintf(buf, "JIG UART OFF\n"); |
| case ATTACHED_DEV_JIG_UART_OFF_VB_MUIC: |
| return sprintf(buf, "JIG UART OFF/VB\n"); |
| case ATTACHED_DEV_JIG_UART_ON_MUIC: |
| return sprintf(buf, "JIG UART ON\n"); |
| case ATTACHED_DEV_JIG_UART_ON_VB_MUIC: |
| return sprintf(buf, "JIG UART ON/VB\n"); |
| case ATTACHED_DEV_JIG_USB_OFF_MUIC: |
| return sprintf(buf, "JIG USB OFF\n"); |
| case ATTACHED_DEV_JIG_USB_ON_MUIC: |
| return sprintf(buf, "JIG USB ON\n"); |
| case ATTACHED_DEV_DESKDOCK_MUIC: |
| return sprintf(buf, "DESKDOCK\n"); |
| case ATTACHED_DEV_AUDIODOCK_MUIC: |
| return sprintf(buf, "AUDIODOCK\n"); |
| case ATTACHED_DEV_CHARGING_CABLE_MUIC: |
| return sprintf(buf, "PS CABLE\n"); |
| case ATTACHED_DEV_AFC_CHARGER_5V_MUIC: |
| case ATTACHED_DEV_AFC_CHARGER_9V_MUIC: |
| case ATTACHED_DEV_QC_CHARGER_5V_MUIC: |
| case ATTACHED_DEV_QC_CHARGER_9V_MUIC: |
| return sprintf(buf, "AFC Charger\n"); |
| default: |
| break; |
| } |
| |
| return sprintf(buf, "UNKNOWN\n"); |
| } |
| |
| static ssize_t s2mu004_muic_show_audio_path(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| return 0; |
| } |
| |
| static ssize_t s2mu004_muic_set_audio_path(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| return 0; |
| } |
| |
| static ssize_t s2mu004_muic_show_apo_factory(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| const char *mode; |
| |
| /* true: Factory mode, false: not Factory mode */ |
| if (muic_pdata->is_factory_start) |
| mode = "FACTORY_MODE"; |
| else |
| mode = "NOT_FACTORY_MODE"; |
| |
| pr_info("%s : %s\n", |
| __func__, mode); |
| |
| return sprintf(buf, "%s\n", mode); |
| } |
| |
| static ssize_t s2mu004_muic_set_apo_factory(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| |
| /* "FACTORY_START": factory mode */ |
| if (!strncmp(buf, "FACTORY_START", 13)) |
| muic_pdata->is_factory_start = true; |
| else |
| pr_info("%s Wrong command\n", __func__); |
| |
| return count; |
| } |
| |
| static ssize_t muic_show_vbus_value(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *muic_pdata = muic_data->pdata; |
| struct i2c_client *i2c = muic_data->i2c; |
| int val = 0; |
| u8 ret, vbadc, afc_ctrl = 0; |
| |
| if ((muic_pdata->attached_dev != ATTACHED_DEV_AFC_CHARGER_9V_MUIC) |
| & (muic_pdata->attached_dev != ATTACHED_DEV_QC_CHARGER_9V_MUIC)) { |
| /* Set AFC_EN, VB_ADC_EN to true in case of did not prepared afc |
| * for PD charger or Normal TA with flag afc_disable |
| */ |
| pr_info("%s: Set AFC_EN, VB_ADC_ON\n", __func__); |
| afc_ctrl = s2mu004_i2c_read_byte(i2c, S2MU004_REG_AFC_CTRL1); |
| afc_ctrl |= (MUIC_AFC_CTRL1_AFC_EN_MASK|MUIC_AFC_CTRL1_VB_ADC_EN_MASK); |
| s2mu004_i2c_write_byte(i2c, S2MU004_REG_AFC_CTRL1, afc_ctrl); |
| mdelay(10); |
| afc_ctrl = s2mu004_i2c_read_byte(i2c, S2MU004_REG_AFC_CTRL1); |
| } |
| |
| /* Read VBADC : must be read after afc prepared */ |
| ret = s2mu004_i2c_read_byte(i2c, S2MU004_REG_AFC_STATUS); |
| if (ret < 0) |
| pr_err("%s err read AFC STATUS(0x%2x)\n", __func__, ret); |
| |
| vbadc = ret & STATUS_VBADC_MASK; |
| pr_info("%s vbadc:0x%x, afc_ctrl:0x%x cable:(%d)\n", |
| __func__, vbadc, afc_ctrl, muic_pdata->attached_dev); |
| |
| switch (vbadc) { |
| case VBADC_5_3V: |
| case VBADC_5_7V_6_3V: |
| val = 5; |
| break; |
| case VBADC_8_7V_9_3V: |
| case VBADC_9_7V_10_3V: |
| val = 9; |
| break; |
| default: |
| break; |
| } |
| |
| /* NOTE: If enter this statement with 9V, voltage would be decreased to 5V */ |
| if ((muic_pdata->attached_dev != ATTACHED_DEV_AFC_CHARGER_9V_MUIC) & |
| (muic_pdata->attached_dev != ATTACHED_DEV_QC_CHARGER_9V_MUIC)) { |
| /* Clear AFC_EN, VB_ADC_EN */ |
| pr_info("%s: Clear AFC_EN, VB_ADC_ON\n", __func__); |
| afc_ctrl = s2mu004_i2c_read_byte(i2c, S2MU004_REG_AFC_CTRL1); |
| afc_ctrl &= ~(MUIC_AFC_CTRL1_AFC_EN_MASK|MUIC_AFC_CTRL1_VB_ADC_EN_MASK); |
| s2mu004_i2c_write_byte(i2c, S2MU004_REG_AFC_CTRL1, afc_ctrl); |
| afc_ctrl = s2mu004_i2c_read_byte(i2c, S2MU004_REG_AFC_CTRL1); |
| } |
| |
| pr_info("%s VBUS:%d, afc_ctrl:0x%x\n", __func__, val, afc_ctrl); |
| |
| if (val > 0) |
| return sprintf(buf, "%dV\n", val); |
| |
| return sprintf(buf, "UNKNOWN\n"); |
| } |
| |
| #if IS_ENABLED(CONFIG_HV_MUIC_S2MU004_AFC) |
| static ssize_t s2mu004_muic_show_afc_disable(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *pdata = muic_data->pdata; |
| |
| if (pdata->afc_disable) { |
| pr_info("%s AFC DISABLE\n", __func__); |
| return sprintf(buf, "1\n"); |
| } |
| |
| pr_info("%s AFC ENABLE", __func__); |
| return sprintf(buf, "0\n"); |
| } |
| |
| static ssize_t s2mu004_muic_set_afc_disable(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| struct muic_platform_data *pdata = muic_data->pdata; |
| bool curr_val = pdata->afc_disable; |
| int param_val, ret = 0; |
| #if IS_ENABLED(CONFIG_MUIC_MANAGER) |
| struct muic_interface_t *muic_if = (struct muic_interface_t *)muic_data->if_data; |
| int mdev = 0; |
| #endif /* CONFIG_MUIC_MANAGER */ |
| union power_supply_propval psy_val; |
| |
| mutex_lock(&muic_data->muic_mutex); |
| |
| if (!strncasecmp(buf, "1", 1)) |
| pdata->afc_disable = true; |
| else if (!strncasecmp(buf, "0", 1)) |
| pdata->afc_disable = false; |
| else |
| pr_warn("%s invalid value\n", __func__); |
| |
| #if IS_ENABLED(CONFIG_MUIC_MANAGER) |
| param_val = pdata->afc_disable ? '1' : '0'; |
| #endif |
| |
| #ifdef CM_OFFSET |
| ret = sec_set_param(CM_OFFSET + 1, (char)param_val); |
| if (ret < 0) { |
| pr_err("%s:set_param failed - %02x:%02x(%d)\n", |
| __func__, param_val, curr_val, ret); |
| pdata->afc_disable = curr_val; |
| return ret; |
| } |
| #else |
| pr_err("%s:set_param is NOT supported! - %02x:%02x(%d)\n", |
| __func__, param_val, curr_val, ret); |
| #endif |
| |
| psy_val.intval = param_val; |
| psy_do_property("battery", set, POWER_SUPPLY_EXT_PROP_HV_DISABLE, psy_val); |
| |
| pr_info("%s afc_disable(%d)\n", __func__, pdata->afc_disable); |
| |
| /* FIXME: for factory self charging test (AFC-> NORMAL TA) */ |
| #ifdef CONFIG_MUIC_MANAGER |
| mdev = muic_manager_get_legacy_dev(muic_if); |
| |
| /* In LCiA charge test, There would be abnormal uart disconnection in |
| * case of afc_disable (0) after 619K insertion. With 619K JIG, there |
| * should be no re-detect chg interrupt which makes muic path open |
| */ |
| if (pdata->is_factory_start && (mdev != ATTACHED_DEV_JIG_UART_ON_MUIC)) { |
| /* Do not enter with 619K in FAC binary */ |
| pr_info("%s re-detect chg (mdev:%d)\n", __func__, mdev); |
| |
| MUIC_PDATA_FUNC(muic_if->reset_afc_register, muic_data, &ret); |
| |
| MUIC_PDATA_FUNC_MULTI_PARAM(muic_if->control_rid_adc, |
| muic_data, S2MU004_ENABLE, &ret); |
| mdelay(50); |
| |
| MUIC_PDATA_FUNC_MULTI_PARAM(muic_if->control_rid_adc, |
| muic_data, S2MU004_DISABLE, &ret); |
| mdelay(50); |
| |
| MUIC_PDATA_FUNC(muic_if->bcd_rescan, muic_data, &ret); |
| pr_info("%s re-detect chg done\n", __func__); |
| |
| /* TODO: When closing charge test, there would be afc_disable 0 |
| * It needs to set is_afc_muic_ready to false in order to |
| * detect afc 9V again |
| */ |
| if (!pdata->afc_disable) { |
| pr_info("%s detach for 9V re-detection\n", __func__); |
| muic_core_handle_detach(muic_data->pdata); |
| } |
| /* Needs to 150ms after rescan */ |
| mdelay(150); |
| } |
| #else |
| if (muic_data->is_factory_start) |
| pr_info("%s re-detect chg\n", __func__); |
| |
| muic_core_handle_detach(muic_data->pdata); |
| s2mu004_muic_detect_dev(muic_data); |
| #endif |
| |
| mutex_unlock(&muic_data->muic_mutex); |
| |
| return count; |
| } |
| |
| #if IS_ENABLED(CONFIG_HV_MUIC_VOLTAGE_CTRL) |
| static ssize_t muic_store_afc_set_voltage(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| if (!strncasecmp(buf, "5V", 2)) |
| hv_muic_change_afc_voltage(MUIC_HV_5V); |
| else if (!strncasecmp(buf, "9V", 2)) |
| hv_muic_change_afc_voltage(MUIC_HV_9V); |
| else |
| pr_warn("%s invalid value : %s\n", __func__, buf); |
| |
| return count; |
| } |
| #endif /* CONFIG_HV_MUIC_VOLTAGE_CTRL */ |
| #endif /* CONFIG_HV_MUIC_S2MU004_AFC */ |
| |
| #if IS_ENABLED(CONFIG_HICCUP_CHARGER) |
| static ssize_t hiccup_show(struct device *dev, |
| struct device_attribute *attr, char *buf) |
| { |
| return sprintf(buf, "ENABLE\n"); |
| } |
| |
| static ssize_t hiccup_store(struct device *dev, |
| struct device_attribute *attr, const char *buf, size_t count) |
| { |
| struct s2mu004_muic_data *muic_data = dev_get_drvdata(dev); |
| |
| if (!strncasecmp(buf, "DISABLE", 7)) { |
| muic_data->is_hiccup_mode = false; |
| s2mu004_muic_com_to_open(muic_data); |
| } else |
| pr_warn("%s invalid com : %s\n", __func__, buf); |
| |
| return count; |
| } |
| #endif /* CONFIG_HICCUP_CHARGER */ |
| |
| static DEVICE_ATTR(uart_en, 0664, s2mu004_muic_show_uart_en, |
| s2mu004_muic_set_uart_en); |
| static DEVICE_ATTR(uart_sel, 0664, s2mu004_muic_show_uart_sel, |
| s2mu004_muic_set_uart_sel); |
| static DEVICE_ATTR(usb_sel, 0664, s2mu004_muic_show_usb_sel, |
| s2mu004_muic_set_usb_sel); |
| static DEVICE_ATTR(adc, 0664, s2mu004_muic_show_adc, NULL); |
| #if IS_ENABLED(DEBUG_MUIC) |
| static DEVICE_ATTR(mansw, 0664, s2mu004_muic_show_mansw, NULL); |
| static DEVICE_ATTR(dump_registers, 0664, s2mu004_muic_show_registers, NULL); |
| static DEVICE_ATTR(int_status, 0664, s2mu004_muic_show_interrupt_status, NULL); |
| #endif |
| static DEVICE_ATTR(usb_state, 0664, s2mu004_muic_show_usb_state, NULL); |
| #if IS_ENABLED(CONFIG_USB_HOST_NOTIFY) |
| static DEVICE_ATTR(otg_test, 0664, |
| s2mu004_muic_show_otg_test, s2mu004_muic_set_otg_test); |
| #endif |
| static DEVICE_ATTR(attached_dev, 0664, s2mu004_muic_show_attached_dev, NULL); |
| static DEVICE_ATTR(audio_path, 0664, |
| s2mu004_muic_show_audio_path, s2mu004_muic_set_audio_path); |
| static DEVICE_ATTR(apo_factory, 0664, |
| s2mu004_muic_show_apo_factory, |
| s2mu004_muic_set_apo_factory); |
| static DEVICE_ATTR(usb_en, 0664, |
| s2mu004_muic_show_usb_en, |
| s2mu004_muic_set_usb_en); |
| static DEVICE_ATTR(vbus_value, 0444, muic_show_vbus_value, NULL); |
| #if IS_ENABLED(CONFIG_HV_MUIC_S2MU004_AFC) |
| static DEVICE_ATTR(afc_disable, 0664, |
| s2mu004_muic_show_afc_disable, s2mu004_muic_set_afc_disable); |
| #if IS_ENABLED(CONFIG_HV_MUIC_VOLTAGE_CTRL) |
| static DEVICE_ATTR(afc_set_voltage, 0220, |
| NULL, muic_store_afc_set_voltage); |
| #endif /* CONFIG_HV_MUIC_VOLTAGE_CTRL */ |
| #endif /* CONFIG_HV_MUIC_S2MU004_AFC */ |
| #if IS_ENABLED(CONFIG_HICCUP_CHARGER) |
| static DEVICE_ATTR_RW(hiccup); |
| #endif /* CONFIG_HICCUP_CHARGER */ |
| |
| static struct attribute *s2mu004_muic_attributes[] = { |
| &dev_attr_uart_en.attr, |
| &dev_attr_uart_sel.attr, |
| &dev_attr_usb_sel.attr, |
| &dev_attr_adc.attr, |
| #if IS_ENABLED(DEBUG_MUIC) |
| &dev_attr_mansw.attr, |
| &dev_attr_dump_registers.attr, |
| &dev_attr_int_status.attr, |
| #endif |
| &dev_attr_usb_state.attr, |
| #if IS_ENABLED(CONFIG_USB_HOST_NOTIFY) |
| &dev_attr_otg_test.attr, |
| #endif |
| &dev_attr_attached_dev.attr, |
| &dev_attr_audio_path.attr, |
| &dev_attr_apo_factory.attr, |
| &dev_attr_usb_en.attr, |
| &dev_attr_vbus_value.attr, |
| #if IS_ENABLED(CONFIG_HV_MUIC_S2MU004_AFC) |
| &dev_attr_afc_disable.attr, |
| #if IS_ENABLED(CONFIG_HV_MUIC_VOLTAGE_CTRL) |
| &dev_attr_afc_set_voltage.attr, |
| #endif /* CONFIG_HV_MUIC_VOLTAGE_CTRL */ |
| #endif /* CONFIG_HV_MUIC_S2MU004_AFC */ |
| #if IS_ENABLED(CONFIG_HICCUP_CHARGER) |
| &dev_attr_hiccup.attr, |
| #endif /* CONFIG_HICCUP_CHARGER */ |
| NULL |
| }; |
| |
| static const struct attribute_group s2mu004_muic_group = { |
| .attrs = s2mu004_muic_attributes, |
| }; |
| |
| int s2mu004_muic_init_sysfs(struct s2mu004_muic_data *muic_data) |
| { |
| int ret; |
| /* create sysfs group */ |
| muic_data->switch_device = sec_device_find("switch"); |
| |
| if (muic_data->switch_device == NULL) |
| muic_data->switch_device = sec_device_create(NULL, "switch"); |
| |
| if (IS_ERR(muic_data->switch_device)) { |
| pr_err("%s Failed to create device(switch)!\n", __func__); |
| ret = -ENODEV; |
| return ret; |
| } |
| |
| ret = sysfs_create_group(&muic_data->switch_device->kobj, &s2mu004_muic_group); |
| if (ret) { |
| pr_err("failed to create sysfs\n"); |
| return ret; |
| } |
| dev_set_drvdata(muic_data->switch_device, muic_data); |
| return ret; |
| } |
| |
| void s2mu004_muic_deinit_sysfs(struct s2mu004_muic_data *muic_data) |
| { |
| if (muic_data->switch_device) |
| sysfs_remove_group(&muic_data->switch_device->kobj, &s2mu004_muic_group); |
| } |