/*
* debugfs.c - debug fs access support
*
* Copyright (c) 2015-2016, NVIDIA CORPORATION. All rights reserved.
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
* This program is distributed in the hope 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, see .
*/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "isc-mgr-priv.h"
#include "isc-dev-priv.h"
static int isc_mgr_status_show(struct seq_file *s, void *data)
{
struct isc_mgr_priv *isc_mgr = s->private;
struct isc_mgr_client *isc_dev;
if (isc_mgr == NULL)
return 0;
pr_info("%s - %s\n", __func__, isc_mgr->devname);
if (list_empty(&isc_mgr->dev_list)) {
seq_printf(s, "%s: No devices supported.\n", isc_mgr->devname);
return 0;
}
mutex_lock(&isc_mgr->mutex);
list_for_each_entry_reverse(isc_dev, &isc_mgr->dev_list, list) {
seq_printf(s, " %02d -- @0x%02x, %02d, %d, %s\n",
isc_dev->id,
isc_dev->cfg.addr,
isc_dev->cfg.reg_bits,
isc_dev->cfg.val_bits,
isc_dev->cfg.drv_name
);
}
mutex_unlock(&isc_mgr->mutex);
return 0;
}
static ssize_t isc_mgr_attr_set(struct file *s,
const char __user *user_buf, size_t count, loff_t *ppos)
{
return count;
}
static int isc_mgr_debugfs_open(struct inode *inode, struct file *file)
{
return single_open(file, isc_mgr_status_show, inode->i_private);
}
static const struct file_operations isc_mgr_debugfs_fops = {
.open = isc_mgr_debugfs_open,
.read = seq_read,
.write = isc_mgr_attr_set,
.llseek = seq_lseek,
.release = single_release,
};
static int pwr_on_get(void *data, u64 *val)
{
struct isc_mgr_priv *isc_mgr = data;
if (isc_mgr->pdata == NULL || !isc_mgr->pdata->num_pwr_gpios) {
*val = 0ULL;
return 0;
}
*val = (isc_mgr->pwr_state & (BIT(28) - 1)) |
((isc_mgr->pdata->num_pwr_gpios & 0x0f) << 28);
return 0;
}
static int pwr_on_set(void *data, u64 val)
{
return isc_mgr_power_up((struct isc_mgr_priv *)data, val);
}
DEFINE_SIMPLE_ATTRIBUTE(pwr_on_fops, pwr_on_get, pwr_on_set, "0x%02llx\n");
static int pwr_off_get(void *data, u64 *val)
{
struct isc_mgr_priv *isc_mgr = data;
if (isc_mgr->pdata == NULL || !isc_mgr->pdata->num_pwr_gpios) {
*val = 0ULL;
return 0;
}
*val = (~isc_mgr->pwr_state) & (BIT(isc_mgr->pdata->num_pwr_gpios) - 1);
*val = (*val & (BIT(28) - 1)) |
((isc_mgr->pdata->num_pwr_gpios & 0x0f) << 28);
return 0;
}
static int pwr_off_set(void *data, u64 val)
{
return isc_mgr_power_down((struct isc_mgr_priv *)data, val);
}
DEFINE_SIMPLE_ATTRIBUTE(pwr_off_fops, pwr_off_get, pwr_off_set, "0x%02llx\n");
int isc_mgr_debugfs_init(struct isc_mgr_priv *isc_mgr)
{
struct dentry *d;
dev_dbg(isc_mgr->dev, "%s %s\n", __func__, isc_mgr->devname);
isc_mgr->d_entry = debugfs_create_dir(
isc_mgr->devname, NULL);
if (isc_mgr->d_entry == NULL) {
dev_err(isc_mgr->dev, "%s: create dir failed\n", __func__);
return -ENOMEM;
}
d = debugfs_create_file("map", S_IRUGO|S_IWUSR, isc_mgr->d_entry,
(void *)isc_mgr, &isc_mgr_debugfs_fops);
if (!d)
goto debugfs_init_err;
d = debugfs_create_file("pwr-on", S_IRUGO|S_IWUSR, isc_mgr->d_entry,
(void *)isc_mgr, &pwr_on_fops);
if (!d)
goto debugfs_init_err;
d = debugfs_create_file("pwr-off", S_IRUGO|S_IWUSR, isc_mgr->d_entry,
(void *)isc_mgr, &pwr_off_fops);
if (!d)
goto debugfs_init_err;
return 0;
debugfs_init_err:
dev_err(isc_mgr->dev, "%s: create file failed\n", __func__);
debugfs_remove_recursive(isc_mgr->d_entry);
isc_mgr->d_entry = NULL;
return -ENOMEM;
}
int isc_mgr_debugfs_remove(struct isc_mgr_priv *isc_mgr)
{
if (isc_mgr->d_entry == NULL)
return 0;
debugfs_remove_recursive(isc_mgr->d_entry);
isc_mgr->d_entry = NULL;
return 0;
}
static int i2c_val_get(void *data, u64 *val)
{
struct isc_dev_info *isc_dev = data;
u8 temp = 0;
if (isc_dev_raw_rd(isc_dev, isc_dev->reg_off, 0, &temp, 1)) {
dev_err(isc_dev->dev, "ERR:%s failed\n", __func__);
return -EIO;
}
*val = (u64)temp;
return 0;
}
static int i2c_val_set(void *data, u64 val)
{
struct isc_dev_info *isc_dev = data;
u8 temp[3];
temp[2] = val & 0xff;
if (isc_dev_raw_wr(isc_dev, isc_dev->reg_off, temp, 1)) {
dev_err(isc_dev->dev, "ERR:%s failed\n", __func__);
return -EIO;
}
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(isc_val_fops, i2c_val_get, i2c_val_set, "0x%02llx\n");
static int i2c_oft_get(void *data, u64 *val)
{
struct isc_dev_info *isc_dev = data;
*val = (u64)isc_dev->reg_off;
return 0;
}
static int i2c_oft_set(void *data, u64 val)
{
struct isc_dev_info *isc_dev = data;
isc_dev->reg_off = (typeof (isc_dev->reg_off))val;
return 0;
}
DEFINE_SIMPLE_ATTRIBUTE(isc_oft_fops, i2c_oft_get, i2c_oft_set, "0x%02llx\n");
int isc_dev_debugfs_init(struct isc_dev_info *isc_dev)
{
struct isc_mgr_priv *isc_mgr = NULL;
struct dentry *d;
dev_dbg(isc_dev->dev, "%s %s\n", __func__, isc_dev->devname);
if (isc_dev->pdata)
isc_mgr = dev_get_drvdata(isc_dev->pdata->pdev);
isc_dev->d_entry = debugfs_create_dir(
isc_dev->devname,
isc_mgr ? isc_mgr->d_entry : NULL);
if (isc_dev->d_entry == NULL) {
dev_err(isc_dev->dev, "%s: create dir failed\n", __func__);
return -ENOMEM;
}
d = debugfs_create_file("val", S_IRUGO|S_IWUSR, isc_dev->d_entry,
(void *)isc_dev, &isc_val_fops);
if (!d) {
dev_err(isc_dev->dev, "%s: create file failed\n", __func__);
debugfs_remove_recursive(isc_dev->d_entry);
isc_dev->d_entry = NULL;
}
d = debugfs_create_file("offset", S_IRUGO|S_IWUSR, isc_dev->d_entry,
(void *)isc_dev, &isc_oft_fops);
if (!d) {
dev_err(isc_dev->dev, "%s: create file failed\n", __func__);
debugfs_remove_recursive(isc_dev->d_entry);
isc_dev->d_entry = NULL;
}
return 0;
}
int isc_dev_debugfs_remove(struct isc_dev_info *isc_dev)
{
if (isc_dev->d_entry == NULL)
return 0;
debugfs_remove_recursive(isc_dev->d_entry);
isc_dev->d_entry = NULL;
return 0;
}