intel_scu_mip: Add mip sysfs interface
authorShijie Zhang <shijie.zhang@intel.com>
Tue, 10 Apr 2012 14:19:34 +0000 (22:19 +0800)
committerbuildbot <buildbot@intel.com>
Thu, 12 Apr 2012 23:37:24 +0000 (16:37 -0700)
BZ: 30963

This patch adds sysfs interface for intel_scu_mip driver, which can be
used for debugging and testing of mip read/write.

Change-Id: Iae052d7773f5a056feaecaabc3cfff4e47a301a6
Signed-off-by: Shijie Zhang <shijie.zhang@intel.com>
Reviewed-on: http://android.intel.com:8080/42863
Reviewed-by: Du, Alek <alek.du@intel.com>
Reviewed-by: Yang, Bin <bin.yang@intel.com>
Tested-by: Wang, Zhifeng <zhifeng.wang@intel.com>
Reviewed-by: buildbot <buildbot@intel.com>
Tested-by: buildbot <buildbot@intel.com>
drivers/platform/x86/intel_scu_mip.c

index 336a3c9..d9dc9be 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/ipc_device.h>
+#include <linux/fs.h>
 #include <asm/intel_scu_ipc.h>
 
 #define IPC_MIP_BASE     0xFFFD8000    /* sram base address for mip accessing*/
@@ -116,18 +117,249 @@ fail:
 }
 EXPORT_SYMBOL(intel_scu_ipc_write_umip);
 
+
+#define MAX_DATA_NR 8
+#define MIP_CMD_LEN 11
+
+enum {
+       MIP_DBG_DATA,
+       MIP_DBG_LEN,
+       MIP_DBG_OFFSET,
+       MIP_DBG_ISSIGNED,
+       MIP_DBG_ERROR,
+};
+
+static u8 mip_data[MAX_DATA_NR];
+static int valid_data_nr;
+static int mip_len;
+static int mip_offset;
+static int mip_issigned;
+static int mip_dbg_error;
+static char mip_cmd[MIP_CMD_LEN];
+
+static char *mip_msg_format[] = {
+       "data[%d]: %#x\n",
+       "len: %d\n",
+       "offset: %#x\n",
+       "issigned: %d\n",
+       "error: %d\n",
+};
+
+static int mip_generic_show(char *buf, int type, int *data)
+{
+       int i, buf_size;
+       int ret = 0;
+
+       switch (type) {
+       case MIP_DBG_DATA:
+               for (i = 0; i < valid_data_nr; i++) {
+                       buf_size = PAGE_SIZE - ret;
+                       ret += snprintf(buf + ret, buf_size,
+                                       mip_msg_format[type],
+                                       i, mip_data[i]);
+               }
+               break;
+       case MIP_DBG_LEN:
+       case MIP_DBG_OFFSET:
+       case MIP_DBG_ISSIGNED:
+       case MIP_DBG_ERROR:
+               ret = snprintf(buf, PAGE_SIZE, mip_msg_format[type], *data);
+               break;
+       default:
+               break;
+       }
+
+       return ret;
+}
+
+static void mip_generic_store(const char *buf, int type, int *data)
+{
+       int i, ret;
+
+       if (type == MIP_DBG_DATA) {
+               u32 t[MAX_DATA_NR];
+
+               valid_data_nr = 0;
+               memset(mip_data, 0, sizeof(mip_data));
+
+               ret = sscanf(buf, "%x %x %x %x %x %x %x %x", &t[0], &t[1],
+                               &t[2], &t[3], &t[4], &t[5], &t[6], &t[7]);
+               if (ret == 0 || ret > MAX_DATA_NR) {
+                       mip_dbg_error = -EINVAL;
+                       return;
+               } else {
+                       for (i = 0; i < ret; i++)
+                               mip_data[i] = (u8)t[i];
+                       valid_data_nr = ret;
+               }
+       } else {
+               *data = 0;
+               switch (type) {
+               case MIP_DBG_OFFSET:
+                       ret = sscanf(buf, "%x", data);
+                       break;
+               case MIP_DBG_LEN:
+               case MIP_DBG_ISSIGNED:
+                       ret = sscanf(buf, "%d", data);
+                       break;
+               default:
+                       ret = -1;
+                       break;
+               }
+       }
+
+       if (ret)
+               mip_dbg_error = 0;
+       else
+               mip_dbg_error = -EINVAL;
+
+       return;
+}
+
+static ssize_t mip_data_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return mip_generic_show(buf, MIP_DBG_DATA, NULL);
+}
+
+static ssize_t mip_data_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       mip_generic_store(buf, MIP_DBG_DATA, NULL);
+       return size;
+}
+
+static ssize_t mip_len_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return mip_generic_show(buf, MIP_DBG_LEN, &mip_len);
+}
+
+static ssize_t mip_len_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       mip_generic_store(buf, MIP_DBG_LEN, &mip_len);
+       return size;
+}
+
+static ssize_t mip_offset_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return mip_generic_show(buf, MIP_DBG_OFFSET, &mip_offset);
+}
+
+static ssize_t mip_offset_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       mip_generic_store(buf, MIP_DBG_OFFSET, &mip_offset);
+       return size;
+}
+
+static ssize_t mip_issigned_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return mip_generic_show(buf, MIP_DBG_ISSIGNED, &mip_issigned);
+}
+
+static ssize_t mip_issigned_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+       mip_generic_store(buf, MIP_DBG_ISSIGNED, &mip_issigned);
+       return size;
+}
+
+static ssize_t mip_error_show(struct device *dev,
+               struct device_attribute *attr, char *buf)
+{
+       return mip_generic_show(buf, MIP_DBG_ERROR, &mip_dbg_error);
+}
+
+static ssize_t mip_cmd_store(struct device *dev,
+               struct device_attribute *attr, const char *buf, size_t size)
+{
+
+       int ret;
+
+       memset(mip_cmd, 0, sizeof(mip_cmd));
+
+       ret = sscanf(buf, "%10s", mip_cmd);
+       if (ret == 0) {
+               mip_dbg_error = -EINVAL;
+               goto end;
+       }
+
+       if (!strncmp("read_mip", mip_cmd, MIP_CMD_LEN)) {
+               memset(mip_data, 0, sizeof(mip_data));
+               ret = intel_scu_ipc_read_mip(mip_data, mip_len, mip_offset,
+                               mip_issigned);
+               if (!ret)
+                       valid_data_nr = mip_len;
+
+       } else if (!strncmp("write_umip", mip_cmd, MIP_CMD_LEN)) {
+               if (mip_len == valid_data_nr) {
+                       ret = intel_scu_ipc_write_umip(mip_data, mip_len,
+                                       mip_offset);
+               } else
+                       goto error;
+       } else
+               goto error;
+
+       if (ret)
+               goto error;
+       else
+               goto end;
+
+error:
+       mip_dbg_error = -EINVAL;
+
+end:
+       return size;
+}
+
+static DEVICE_ATTR(data, S_IRUGO|S_IWUSR, mip_data_show, mip_data_store);
+static DEVICE_ATTR(len, S_IRUGO|S_IWUSR, mip_len_show, mip_len_store);
+static DEVICE_ATTR(offset, S_IRUGO|S_IWUSR, mip_offset_show, mip_offset_store);
+static DEVICE_ATTR(issigned, S_IRUGO|S_IWUSR, mip_issigned_show,
+               mip_issigned_store);
+static DEVICE_ATTR(cmd, S_IWUSR, NULL, mip_cmd_store);
+static DEVICE_ATTR(error, S_IRUGO, mip_error_show, NULL);
+
+static struct attribute *mip_attrs[] = {
+       &dev_attr_data.attr,
+       &dev_attr_len.attr,
+       &dev_attr_offset.attr,
+       &dev_attr_issigned.attr,
+       &dev_attr_cmd.attr,
+       &dev_attr_error.attr,
+       NULL,
+};
+
+static struct attribute_group mip_attr_group = {
+       .name = "mip_debug",
+       .attrs = mip_attrs,
+};
+
 static int __devinit intel_mip_probe(struct ipc_device *ipcdev)
 {
+       int ret;
+
        intel_mip_base = ioremap_nocache(IPC_MIP_BASE, IPC_MIP_MAX_ADDR);
        if (!intel_mip_base)
                return -ENOMEM;
 
-       return 0;
+       ret = sysfs_create_group(&ipcdev->dev.kobj, &mip_attr_group);
+       if (ret) {
+               dev_err(&ipcdev->dev, "Failed to create mip sysfs interface\n");
+               iounmap(intel_mip_base);
+       }
+
+       return ret;
 }
 
 static int __devexit intel_mip_remove(struct ipc_device *ipcdev)
 {
        iounmap(intel_mip_base);
+       sysfs_remove_group(&ipcdev->dev.kobj, &mip_attr_group);
        return 0;
 }
 
@@ -157,6 +389,5 @@ module_init(mip_module_init);
 module_exit(mip_module_exit);
 
 MODULE_AUTHOR("Shijie Zhang <shijie.zhang@intel.com>");
-MODULE_AUTHOR("Sreedhara DS <sreedhara.ds@intel.com>");
 MODULE_DESCRIPTION("Intel SCU MIP driver");
 MODULE_LICENSE("GPL v2");