android_kernel_samsung_on5x.../drivers/muic/universal/muic_sysfs.c
2018-06-19 23:16:04 +02:00

520 lines
13 KiB
C

/*
* muic_sysfs.c
*
* Copyright (C) 2014 Samsung Electronics
* Thomas Ryu <smilesr.ryu@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_debug.h"
#include "muic_apis.h"
#include "muic_regmap.h"
static ssize_t muic_show_uart_en(struct device *dev,
struct device_attribute *attr,
char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
if (!pmuic->is_rustproof) {
pr_info("%s:%s UART ENABLE\n", MUIC_DEV_NAME, __func__);
return sprintf(buf, "1\n");
}
pr_info("%s:%s UART DISABLE\n", MUIC_DEV_NAME, __func__);
return sprintf(buf, "0\n");
}
static ssize_t muic_set_uart_en(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
if (!strncmp(buf, "1", 1)) {
pmuic->is_rustproof = false;
} else if (!strncmp(buf, "0", 1)) {
pmuic->is_rustproof = true;
} else {
pr_warn("%s:%s invalid value\n", MUIC_DEV_NAME, __func__);
}
pr_info("%s:%s uart_en(%d)\n", MUIC_DEV_NAME, __func__,
!pmuic->is_rustproof);
return count;
}
#if !defined(CONFIG_UART_SEL)
static ssize_t muic_show_uart_sel(struct device *dev,
struct device_attribute *attr,
char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
struct muic_platform_data *pdata = pmuic->pdata;
switch (pdata->uart_path) {
case MUIC_PATH_UART_AP:
pr_info("%s:%s AP\n", MUIC_DEV_NAME, __func__);
return sprintf(buf, "AP\n");
case MUIC_PATH_UART_CP:
pr_info("%s:%s CP\n", MUIC_DEV_NAME, __func__);
return sprintf(buf, "CP\n");
default:
break;
}
pr_info("%s:%s UNKNOWN\n", MUIC_DEV_NAME, __func__);
return sprintf(buf, "UNKNOWN\n");
}
static ssize_t muic_set_uart_sel(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
struct muic_platform_data *pdata = pmuic->pdata;
if (!strncasecmp(buf, "AP", 2)) {
pdata->uart_path = MUIC_PATH_UART_AP;
switch_to_ap_uart(pmuic);
} else if (!strncasecmp(buf, "CP", 2)) {
pdata->uart_path = MUIC_PATH_UART_CP;
switch_to_cp_uart(pmuic);
} else {
pr_warn("%s:%s invalid value\n", MUIC_DEV_NAME, __func__);
}
pr_info("%s:%s uart_path(%d)\n", MUIC_DEV_NAME, __func__,
pdata->uart_path);
return count;
}
static ssize_t muic_show_usb_sel(struct device *dev,
struct device_attribute *attr,
char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
struct muic_platform_data *pdata = pmuic->pdata;
switch (pdata->usb_path) {
case MUIC_PATH_USB_AP:
return sprintf(buf, "PDA\n");
case MUIC_PATH_USB_CP:
return sprintf(buf, "MODEM\n");
default:
break;
}
pr_info("%s:%s UNKNOWN\n", MUIC_DEV_NAME, __func__);
return sprintf(buf, "UNKNOWN\n");
}
static ssize_t muic_set_usb_sel(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
struct muic_platform_data *pdata = pmuic->pdata;
if (!strncasecmp(buf, "PDA", 3)) {
pdata->usb_path = MUIC_PATH_USB_AP;
} else if (!strncasecmp(buf, "MODEM", 5)) {
pdata->usb_path = MUIC_PATH_USB_CP;
} else {
pr_warn("%s:%s invalid value\n", MUIC_DEV_NAME, __func__);
}
pr_info("%s:%s usb_path(%d)\n", MUIC_DEV_NAME, __func__,
pdata->usb_path);
return count;
}
#endif
static ssize_t muic_show_adc(struct device *dev,
struct device_attribute *attr, char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
int ret;
mutex_lock(&pmuic->muic_mutex);
ret = get_adc(pmuic);
mutex_unlock(&pmuic->muic_mutex);
if (ret < 0) {
pr_err("%s:%s err read adc reg(%d)\n", MUIC_DEV_NAME, __func__,
ret);
return sprintf(buf, "UNKNOWN\n");
}
return sprintf(buf, "%x\n", ret);
}
static ssize_t muic_show_usb_state(struct device *dev,
struct device_attribute *attr,
char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
switch (pmuic->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;
}
#ifdef DEBUG_MUIC
static ssize_t muic_show_registers(struct device *dev,
struct device_attribute *attr,
char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
char mesg[256] = "";
mutex_lock(&pmuic->muic_mutex);
muic_read_reg_dump(pmuic, mesg);
mutex_unlock(&pmuic->muic_mutex);
pr_info("%s:%s\n", __func__, mesg);
return sprintf(buf, "%s\n", mesg);
}
static char reg_dump_buf[256];
static ssize_t muic_show_reg_sel(struct device *dev,
struct device_attribute *attr,
char *buf)
{
pr_info("%s:%s\n", __func__, reg_dump_buf);
return sprintf(buf, "%s\n", reg_dump_buf);
}
static ssize_t muic_set_reg_sel(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
int len = strlen(buf);
unsigned int reg_base = 0, reg_num = 0;
int ret = -EINVAL, i = 0;
#if 0 /* For the compatibility in 64 bit */
pr_info("%s:%s -> %s(%d, %d)\n", MUIC_DEV_NAME, __func__,
buf, count, len);
#endif
if (len < 6) {
ret = kstrtoint(buf, 0, &reg_base);
if (ret) {
pr_err("%s: Undefined Regs\n", __func__);
goto err;
}
reg_num = 1;
} else if (len < 10) {
char *ptr;
char reg_buf[8];
strcpy(reg_buf, buf);
ptr = strstr(reg_buf, "++");
*ptr = 0x00;
ret = kstrtoint(reg_buf, 0, &reg_base);
if (ret) {
pr_err("%s: Undefined Regs\n", __func__);
goto err;
}
ret = kstrtoint(ptr + 2, 0, &reg_num);
if (ret) {
pr_err("%s: Undefined Regs\n", __func__);
goto err;
}
} else {
pr_err("%s: Undefined Regs\n", __func__);
goto err;
}
pr_info(" (reg_base,reg_num) = (0x%02x,%d)\n", reg_base, reg_num);
memset(reg_dump_buf, 0x00, sizeof(reg_dump_buf));
while (reg_num--) {
mutex_lock(&pmuic->muic_mutex);
ret = muic_i2c_read_byte(pmuic->i2c, reg_base + i);
mutex_unlock(&pmuic->muic_mutex);
if (ret < 0) {
pr_err("%s:%s err read %d\n", MUIC_DEV_NAME, __func__,
reg_base);
goto err;
}
pr_info(" [%02x] : %02x\n", reg_base, ret);
sprintf(reg_dump_buf + strlen(reg_dump_buf),
" [%02x] : %02x\n", reg_base + i++, ret);
}
err:
return count;
}
#endif
#if defined(CONFIG_USB_HOST_NOTIFY)
static ssize_t muic_show_otg_test(struct device *dev,
struct device_attribute *pattr,
char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
struct regmap_ops *pops = pmuic->regmapdesc->regmapops;
int uattr;
u8 val = 0;
mutex_lock(&pmuic->muic_mutex);
pops->ioctl(pmuic->regmapdesc, GET_OTG_STATUS, NULL, &uattr);
val = regmap_read_value(pmuic->regmapdesc, uattr);
mutex_unlock(&pmuic->muic_mutex);
pr_info("%s val:%x buf%s\n", __func__, val, buf);
if (val < 0) {
pr_err("%s: fail to read muic reg\n", __func__);
return sprintf(buf, "UNKNOWN\n");
}
return sprintf(buf, "%x\n", val);
}
static ssize_t muic_set_otg_test(struct device *dev,
struct device_attribute *pattr,
const char *buf, size_t count)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
struct regmap_ops *pops = pmuic->regmapdesc->regmapops;
struct reg_attr attr;
int uattr;
u8 val;
pr_info("%s buf:%s\n", __func__, buf);
if (!strncmp(buf, "0", 1)) {
val = 0;
pmuic->is_otg_test = true;
} else if (!strncmp(buf, "1", 1)) {
val = 1;
pmuic->is_otg_test = false;
} else {
pr_warn("%s:%s Wrong command\n", MUIC_DEV_NAME, __func__);
return count;
}
mutex_lock(&pmuic->muic_mutex);
pops->ioctl(pmuic->regmapdesc, GET_OTG_STATUS, NULL, &uattr);
_REG_ATTR(&attr, uattr);
val = muic_i2c_read_byte(pmuic->i2c, attr.addr);
val |= attr.mask << attr.bitn;
val |= _ATTR_OVERWRITE_M;
val = regmap_write_value(pmuic->regmapdesc, uattr, val);
mutex_unlock(&pmuic->muic_mutex);
if (val < 0) {
pr_err("%s err writing %s reg(%d)\n", __func__,
regmap_to_name(pmuic->regmapdesc, attr.addr), val);
}
val = 0;
val = muic_i2c_read_byte(pmuic->i2c, attr.addr);
val &= (attr.mask << attr.bitn);
pr_info("%s: %s(0x%02x)\n", __func__,
regmap_to_name(pmuic->regmapdesc, attr.addr), val);
return count;
}
#endif
static ssize_t muic_show_attached_dev(struct device *dev,
struct device_attribute *attr,
char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
pr_info("%s:%s attached_dev:%d\n", MUIC_DEV_NAME, __func__,
pmuic->attached_dev);
switch(pmuic->attached_dev) {
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_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_9V_MUIC:
return sprintf(buf, "AFC charger\n");
default:
break;
}
return sprintf(buf, "UNKNOWN\n");
}
static ssize_t muic_show_audio_path(struct device *dev,
struct device_attribute *attr,
char *buf)
{
return 0;
}
static ssize_t muic_set_audio_path(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
return 0;
}
static ssize_t muic_show_apo_factory(struct device *dev,
struct device_attribute *attr,
char *buf)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
const char *mode;
/* true: Factory mode, false: not Factory mode */
if (pmuic->is_factory_start)
mode = "FACTORY_MODE";
else
mode = "NOT_FACTORY_MODE";
pr_info("%s:%s apo factory=%s\n", MUIC_DEV_NAME, __func__, mode);
return sprintf(buf, "%s\n", mode);
}
static ssize_t muic_set_apo_factory(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
muic_data_t *pmuic = dev_get_drvdata(dev);
const char *mode;
pr_info("%s:%s buf:%s\n", MUIC_DEV_NAME, __func__, buf);
/* "FACTORY_START": factory mode */
if (!strncmp(buf, "FACTORY_START", 13)) {
pmuic->is_factory_start = true;
mode = "FACTORY_MODE";
} else {
pr_warn("%s:%s Wrong command\n", MUIC_DEV_NAME, __func__);
return count;
}
pr_info("%s:%s apo factory=%s\n", MUIC_DEV_NAME, __func__, mode);
return count;
}
static DEVICE_ATTR(uart_en, 0664, muic_show_uart_en, muic_set_uart_en);
#if !defined(CONFIG_UART_SEL)
static DEVICE_ATTR(uart_sel, 0664, muic_show_uart_sel,
muic_set_uart_sel);
static DEVICE_ATTR(usb_sel, 0664,
muic_show_usb_sel, muic_set_usb_sel);
#endif
static DEVICE_ATTR(adc, 0664, muic_show_adc, NULL);
#ifdef DEBUG_MUIC
static DEVICE_ATTR(reg_dump, 0664, muic_show_registers, NULL);
static DEVICE_ATTR(reg_sel, 0664, muic_show_reg_sel, muic_set_reg_sel);
#endif
static DEVICE_ATTR(usb_state, 0664, muic_show_usb_state, NULL);
#if defined(CONFIG_USB_HOST_NOTIFY)
static DEVICE_ATTR(otg_test, 0664,
muic_show_otg_test, muic_set_otg_test);
#endif
static DEVICE_ATTR(attached_dev, 0664, muic_show_attached_dev, NULL);
static DEVICE_ATTR(audio_path, 0664,
muic_show_audio_path, muic_set_audio_path);
static DEVICE_ATTR(apo_factory, 0664,
muic_show_apo_factory,
muic_set_apo_factory);
static struct attribute *muic_attributes[] = {
&dev_attr_uart_en.attr,
#if !defined(CONFIG_UART_SEL)
&dev_attr_uart_sel.attr,
&dev_attr_usb_sel.attr,
#endif
&dev_attr_adc.attr,
#ifdef DEBUG_MUIC
&dev_attr_reg_dump.attr,
&dev_attr_reg_sel.attr,
#endif
&dev_attr_usb_state.attr,
#if defined(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,
NULL
};
const struct attribute_group muic_sysfs_group = {
.attrs = muic_attributes,
};