/* * Copyright (C) 2018 Spreadtrum Communications Inc. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and * may be copied, distributed, and modified under those terms. * * 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. */ #include #include #include #include #include #include #include #include "mdbg_type.h" #include "../sleep/slp_mgr.h" struct wcn_reg_ctl { unsigned int addr; unsigned int len; /* 1: rw_extended; 0:rw_direct */ unsigned int rw_extended; /* * make sure sdio critical buf >512, * but the frame size is larger than 2048 * bytes is not permission in kernel to android */ unsigned int value[256]; }; static ssize_t read_wcn_reg(struct file *file, char __user *user_buf, size_t count, loff_t *ppos) { struct wcn_reg_ctl reg_rd; int i; WCN_INFO("wsh __read_wcn_reg\n"); if (copy_from_user(®_rd, user_buf, sizeof(reg_rd))) { WCN_ERR("reg value copy's ret value is -eFAULT\n"); return -EFAULT; } /* rw_direct SDIO */ if (reg_rd.rw_extended == 0) { for (i = 0; i < reg_rd.len; i++) sprdwcn_bus_aon_readb(reg_rd.addr + i, (unsigned char *) ®_rd.value[i]); } else { /* rw_extended reg */ switch (reg_rd.len) { case 1: sprdwcn_bus_reg_read(reg_rd.addr, ®_rd.value[0], 4); break; default: sprdwcn_bus_direct_read(reg_rd.addr, reg_rd.value, reg_rd.len * 4); break; } } if (copy_to_user(user_buf, ®_rd, sizeof(reg_rd))) { WCN_ERR("reg copy_to_user ret value is -eFAULT\n"); return -EFAULT; } return count; } static ssize_t write_wcn_reg(struct file *file, const char __user *user_buf, size_t count, loff_t *ppos) { struct wcn_reg_ctl reg_wr; int i; WCN_INFO("wsh _write_wcn_reg\n"); if (copy_from_user(®_wr, user_buf, sizeof(reg_wr))) { WCN_ERR("write_wcn_reg copy's ret value is -eFAULT\n"); return -EFAULT; } /* rw_direct SDIO */ if (reg_wr.rw_extended == 0) { for (i = 0; i < reg_wr.len; i++) sprdwcn_bus_aon_writeb(reg_wr.addr + i, (unsigned char)reg_wr.value[i]); } else { /* rw_extended reg */ switch (reg_wr.len) { case 1: sprdwcn_bus_reg_write(reg_wr.addr, ®_wr.value[0], 4); break; default: sprdwcn_bus_direct_write(reg_wr.addr, reg_wr.value, reg_wr.len * 4); break; } } return count; } static const struct file_operations reg_debug_fops = { .read = read_wcn_reg, .write = write_wcn_reg, .open = simple_open, .owner = THIS_MODULE, .llseek = default_llseek, }; static int __init wcn_init_debugfs(void) { struct dentry *ent, *root = debugfs_create_dir("wcn", NULL); if (!root) return -ENXIO; ent = debugfs_create_file("regctl", 0644, (struct dentry *)root, NULL, ®_debug_fops); if (IS_ERR(ent)) return PTR_ERR(ent); return 0; } device_initcall(wcn_init_debugfs);