// SPDX-License-Identifier: (GPL-2.0+ OR MIT) /* * Copyright (c) 2019 Amlogic, Inc. All rights reserved. */ //#define DEBUG #include #include #include #include "host.h" #include "sysfs.h" #define PWR_OFF 0 #define PWR_ON 1 struct dentry *debug_dir; static int gethost_clkrate(struct seq_file *s, void *what) { struct host_module *host = s->private; seq_printf(s, "%u\n", host->clk_rate); return 0; } static ssize_t host_clkrate_write(struct file *file, const char __user *userbuf, size_t count, loff_t *ppos) { struct seq_file *sf = file->private_data; struct host_module *host = sf->private; char buffer[15] = {0}; count = min_t(size_t, count, sizeof(buffer) - 1); if (copy_from_user(buffer, userbuf, count)) return -EFAULT; if (kstrtouint(buffer, 0, &host->clk_rate)) return -EINVAL; return count; } static int host_clkrate_open(struct inode *inode, struct file *file) { return single_open(file, gethost_clkrate, inode->i_private); } static const struct file_operations clkrate_fops = { .open = host_clkrate_open, .read = seq_read, .write = host_clkrate_write, .llseek = seq_lseek, .release = single_release, }; static int health_cnt_show(struct seq_file *s, void *data) { struct host_module *host = s->private; if (host->health_reg) seq_printf(s, "[%u %u]\n", host->pre_cnt, host->cur_cnt); else seq_puts(s, "not support health monitor\n"); return 0; } DEFINE_SHOW_ATTRIBUTE(health_cnt); void host_create_debugfs_files(struct host_module *host) { struct dentry *freq_file; struct host_data *host_data = host->host_data; debug_dir = debugfs_create_dir(host_data->name, NULL); if (!debug_dir) { pr_err("[%s]debugfs_create_dir %s failed..\n", __func__, host_data->name); return; } freq_file = debugfs_create_file("clk_rate", S_IFREG | 0440, debug_dir, host, &clkrate_fops); if (!freq_file) pr_err("[%s]debugfs_create_file failed..\n", __func__); debugfs_create_file("health_cnt", 0444, debug_dir, host, &health_cnt_fops); } void host_destroy_debugfs_files(struct host_module *host) { debugfs_remove_recursive(debug_dir); } static ssize_t pwron_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = 0; unsigned int pwr_on = 0; ret = kstrtouint(buf, 0, &pwr_on); if (ret) return -EINVAL; switch (pwr_on) { case PWR_ON: pm_runtime_get_sync(dev); break; case PWR_OFF: pm_runtime_put_sync(dev); break; default: break; }; return count; } static ssize_t corereset_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct host_module *host = platform_get_drvdata(pdev); int ret = 0; unsigned int core_reset = UINT_MAX; if (IS_ERR_OR_NULL(host)) dev_err(dev, "[%s] cannot found host through dev\n", __func__); else ret = kstrtouint(buf, 0, &core_reset); if (ret) return -EINVAL; if (core_reset == 1) host_core_reset(host); else pr_err("[%s] core_reset value is not 1\n", __func__); return count; } static DEVICE_ATTR_WO(pwron); static DEVICE_ATTR_WO(corereset); void host_create_device_files(struct device *dev) { WARN_ON(device_create_file(dev, &dev_attr_pwron)); WARN_ON(device_create_file(dev, &dev_attr_corereset)); } void host_destroy_device_files(struct device *dev) { device_remove_file(dev, &dev_attr_pwron); device_remove_file(dev, &dev_attr_corereset); }