Baseline update from LYNQ_SDK_ASR_T108_V05.03.01.00(kernel build error.)
Change-Id: I56fc72cd096e82c589920026553170e5cb9692eb
diff --git a/marvell/linux/drivers/misc/mbtk_plat_irq.c b/marvell/linux/drivers/misc/mbtk_plat_irq.c
new file mode 100755
index 0000000..720af18
--- /dev/null
+++ b/marvell/linux/drivers/misc/mbtk_plat_irq.c
@@ -0,0 +1,914 @@
+/*
+ * drivers/soc/zte/plat/plat-zx298501.c
+ *
+ * Copyright (C) 2021 ZTE-TSP
+ *
+ * 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.
+ */
+
+#include <linux/kernel.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/clockchips.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/syscore_ops.h>
+#include <linux/gpio.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/platform_device.h>
+#include <linux/pm_domain.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
+#include <linux/reset.h>
+#include <linux/io.h>
+#include <linux/amba/serial.h>
+#include <linux/serial_reg.h>
+#include <linux/of_device.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/sched/clock.h>
+#include <linux/suspend.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/reboot.h>
+#include <linux/miscdevice.h>
+#include <dt-bindings/soc/mbtk_plat_irq.h>
+#include <uapi/linux/bsp_api.h>
+//#include <linux/soc/sc/common.h>
+/*#include <linux/soc/sc/pcu.h>
+#include <linux/soc/sc/spinlock.h>
+
+
+*/
+/*
+ * we use sysfs to test&debug some system funcs
+ *
+ */
+struct kobject *zx_root_kobj;
+struct kobject *zx_test_kobj;
+struct kobject *zx_pm_kobj;
+
+extern int __init zx_clk_test_init(void);
+extern int __init zx_dma_test_init(void);
+extern int __init zx_icp_test_init(void);
+extern int __init zx_timer_test_init(void);
+
+#define DOUBLE_EINT_DBG 0
+#define EINT_THREAD_TEST 0
+
+#define CONFIG_USE_DEBUG_LED 1
+#define ZX_RESET_TEST 1
+#define ZX_CLK_TEST 1
+#define ZX_PINCTRL_TEST 1
+#define ZX_GPIO_TEST 1
+#define ZX_EINT_TEST 1
+#define ZX_PM_TEST 1
+#if ZX_PM_TEST
+#define PM_RUNTIME_AUTO_TEST 1
+#endif
+#define ZX_SPINLOCK_TEST 0
+#define ZX_PM_QOS_TEST 0
+
+#define TRUE 1
+#define FALSE 0
+
+/*
+ *
+ * some test need device probe
+ */
+struct zx_drv_test
+{
+ struct device *dev;
+#if ZX_RESET_TEST
+ struct reset_control *rst;
+#endif
+
+#if ZX_PINCTRL_TEST
+ struct pinctrl *pctrl;
+ struct pinctrl_state *state0;
+ struct pinctrl_state *state1;
+ struct pinctrl_state *state2;
+#endif
+
+#if ZX_GPIO_TEST
+ int gpio;
+ int gpio2;
+ int gpio3;
+ struct gpio_desc *gd;
+
+#endif
+
+#if ZX_EINT_TEST
+ int eint_irq;
+ int eint_irq2;
+#endif
+
+#if ZX_CLK_TEST
+ struct clk *clk;
+#endif
+};
+
+struct zx_drv_test drv_test = {0};
+
+#define MAX_GPIO_NUM 4
+
+struct MbtkPlatIrq_dev
+{
+ struct device *dev;
+ struct pinctrl *pctrl;
+ int gpio_desc[MAX_GPIO_NUM] ;
+ int release_func_callback[MAX_GPIO_NUM] ;
+ //struct wakeup_source *WakeUp_ws;
+
+};
+
+struct MbtkPlatIrq_dev g_MbtkPlatIrq_dev = {0};
+
+
+
+
+
+
+#if 0//ZX_RESET_TEST
+static void drv_reset_test(struct reset_control *rstc)
+{
+ reset_control_assert(rstc);
+ udelay(10);
+ reset_control_deassert(rstc);
+}
+#endif
+
+#if ZX_EINT_TEST
+#if EINT_THREAD_TEST
+static irqreturn_t test_eint_pri_isr(int irq, void *p)
+{
+ disable_irq_nosync(irq);
+
+ return IRQ_WAKE_THREAD;
+}
+
+static irqreturn_t test_eint_isr(int irq, void *p)
+{
+ static int eint_cnt = 0;
+ if ( pinctrl_select_state(drv_test.pctrl, drv_test.state0) < 0) {
+ pr_err("setting state0 failed\n");
+ }
+
+ irq_set_irq_type(drv_test.eint_irq, gpio_get_value(drv_test.gpio)?IRQ_TYPE_LEVEL_LOW:IRQ_TYPE_LEVEL_HIGH);
+
+ if ( pinctrl_select_state(drv_test.pctrl, drv_test.state1) < 0) {
+ pr_err("setting state0 failed\n");
+ }
+
+ enable_irq(irq);
+
+ pr_info("eint9 get = %d\n", ++eint_cnt);
+
+ return IRQ_HANDLED;
+}
+#else
+static irqreturn_t test_eint_isr(int irq, void *p)
+{
+ static int eint_cnt = 0;
+
+ irq_set_irq_type(drv_test.eint_irq, gpio_get_value(drv_test.gpio)?IRQ_TYPE_LEVEL_LOW:IRQ_TYPE_LEVEL_HIGH);
+
+ //pr_info("eint9 get = %d\n", ++eint_cnt);
+
+ return IRQ_HANDLED;
+}
+#endif
+static irqreturn_t test_eint_isr2(int irq, void *p)
+{
+ static int eint_cnt1 = 0;
+
+ irq_set_irq_type(drv_test.eint_irq2, gpio_get_value(drv_test.gpio2)?IRQ_TYPE_LEVEL_LOW:IRQ_TYPE_LEVEL_HIGH);
+
+ pr_info("eint12 get = %d\n", ++eint_cnt1);
+
+ return IRQ_HANDLED;
+}
+
+#endif
+
+
+
+/*-------------------------------------------------------------------*/
+#define MBTK_IRQ_MINOR (170)
+#define MBTK_LIBIRQ_MAX (4)
+
+/*
+ * line : request
+ * type : driver use
+ * wake_flag : for wait
+ *
+ */
+struct libirq_info {
+ unsigned int line;
+ unsigned int hirq;
+ unsigned int virq;
+ unsigned int type;
+ int wake;
+ unsigned int used;
+ bool wake_flag;
+ wait_queue_head_t wait;
+ char name[16];
+};
+
+struct libirq_context {
+ unsigned int pending;
+ spinlock_t lock;
+ struct pinctrl *pctrl;
+ struct pinctrl_state *state[MBTK_LIBIRQ_MAX];
+
+ struct device_node *np;
+ struct device_node *ext8in1_np;
+ struct libirq_info info[MBTK_LIBIRQ_MAX];
+};
+static struct libirq_context irq_ctx = {0};
+
+#define line_used(l) irq_ctx.info[l].used
+
+static int irq_line_convert(int line)
+{
+#if 0 //forbid by niening
+ if (line>=4)
+ return EX24_INT + line - 8;
+ else
+ return EX21_INT + line;
+
+
+#else
+ int irq;
+
+ irq = gpio_to_irq(g_MbtkPlatIrq_dev.gpio_desc[line]);
+ if (irq < 0)
+ {
+ pr_err("%s. gpio %d request irq %d failed\n", __func__,g_MbtkPlatIrq_dev.gpio_desc[line], irq);
+
+ }
+
+ return irq;
+
+#endif
+}
+
+static unsigned int irq_type_convert(unsigned int req_type)
+{
+ //printk("--->%s/L%d req_type = %d\n", __FUNCTION__, __LINE__, req_type);
+ if (req_type == 0)
+ return IRQ_TYPE_EDGE_RISING;
+ else if (req_type == 1)
+ return IRQ_TYPE_EDGE_FALLING;
+ else if (req_type == 2)
+ return IRQ_TYPE_LEVEL_HIGH;
+ else if (req_type == 3)
+ return IRQ_TYPE_LEVEL_LOW;
+ else
+ return IRQ_TYPE_NONE;
+}
+
+static int mbkt_irq_map_ext8in1(int hirq, unsigned int type)
+{
+ struct of_phandle_args args;
+
+ args.args_count = 2;
+ args.args[0] = hirq;
+ args.args[1] = type;
+ args.np = irq_ctx.ext8in1_np;
+
+ return irq_create_of_mapping(&args);
+}
+
+static int mbkt_irq_map(int hirq, unsigned int type, unsigned int line)
+{
+ struct of_phandle_args args;
+ int ret = 0;
+#if 0
+ char name[16];
+
+ //if (hirq>=EX8_INT && hirq<=EX15_INT)
+ // return mbkt_irq_map_ext8in1(hirq, type);
+
+ memset(name, 0, sizeof(name));
+ sprintf(name, "%s%d", "gpio_irq", line);
+
+ ret = gpio_request(g_MbtkPlatIrq_dev.gpio_desc[line], name);
+ if(ret < 0)
+ {
+ pr_err("%s. gpio_request for =%d failed\n", __func__,g_MbtkPlatIrq_dev.gpio_desc[line]);
+ }
+
+ gpio_direction_input(g_MbtkPlatIrq_dev.gpio_desc[line]);
+
+ hirq = gpio_to_irq(g_MbtkPlatIrq_dev.gpio_desc[line]);
+
+
+ pr_err("%s. %s=%d, hirq = %d\n", __func__, name, g_MbtkPlatIrq_dev.gpio_desc[line], hirq);
+ irq_ctx.info[line].hirq = hirq;
+#endif
+ args.args_count = 3;
+ args.args[0] = 0;
+ args.args[1] = hirq;
+ args.args[2] = type;
+ args.np = irq_ctx.np;
+
+ return hirq;
+ //return irq_create_of_mapping(&args);
+}
+
+static void mbtk_irq_wait(unsigned int line)
+{
+ struct libirq_info *info = &(irq_ctx.info[line]);
+
+ info->wake_flag = false;
+ wait_event_freezable(info->wait, info->wake_flag);
+}
+
+static void mbtk_irq_wakeup(unsigned int line)
+{
+ struct libirq_info *info = &(irq_ctx.info[line]);
+
+ info->wake_flag = true;
+ wake_up_interruptible(&info->wait);
+}
+
+static irqreturn_t mbtk_irq_isr(int irq, void *priv)
+{
+ struct libirq_info *info = (struct libirq_info *)priv;
+ unsigned int line = info->line;
+ int gpio_value = 0;
+
+ disable_irq_nosync(irq); //add by niening
+
+ gpio_value = gpio_get_value_cansleep(g_MbtkPlatIrq_dev.gpio_desc[line]) ;
+
+ printk("%s/L%d, gpio_value = %d \n", __FUNCTION__, __LINE__, gpio_value);
+ if(info->wake)
+ {
+ pm_wakeup_event(g_MbtkPlatIrq_dev.dev, 2000);
+ }
+
+
+ if(line_used(line)) {
+ irq_ctx.pending |= BIT(line);
+
+ mbtk_irq_wakeup(line);
+ }
+
+
+
+ pr_info("%s:eint get = %d\n", __func__, line);
+
+ enable_irq(irq);//add by niening
+
+ return IRQ_HANDLED;
+}
+
+static int mbtk_irq_open(struct inode *inode, struct file *filp)
+{
+ int error = 0;
+ unsigned int line;
+ struct libirq_info *info;
+
+ line = iminor(inode) - MBTK_IRQ_MINOR;
+
+ filp->private_data = &(irq_ctx.info[line]);
+
+
+ info = (struct libirq_info *)filp->private_data;
+
+ // add by niening for solve upper app restart send install cmd
+
+ if (g_MbtkPlatIrq_dev.release_func_callback[info->line] == TRUE)
+ {
+ pr_err("%s/L%d\n", __FUNCTION__, __LINE__);
+ free_irq(info->virq, info);
+ }
+
+
+ return error;
+}
+
+static int mbtk_irq_release(struct inode *inode, struct file *filp)
+{
+ struct libirq_info *info;
+
+ info = (struct libirq_info *)filp->private_data;
+
+ pr_err("%s/L%d\n", __FUNCTION__, __LINE__);
+
+ if(line_used(info->line)) {
+
+#if 0 // forbid by niening for upper app goto sleep will callback this function
+
+ //irq_set_irq_type(info->virq, IRQ_TYPE_NONE);
+ //free_irq(info->virq, info);
+#endif
+
+ line_used(info->line) = 0;
+ }
+
+ filp->private_data = NULL;
+
+
+ g_MbtkPlatIrq_dev.release_func_callback[info->line] = TRUE;
+ return 0;
+}
+
+static long mbtk_irq_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
+{
+ int error = 0;
+ struct libirq_info *info;
+ int virq;
+ unsigned int type;
+ unsigned int en;
+ int ret = 0;
+ unsigned long flags;
+
+ info = (struct libirq_info *)filp->private_data;
+
+ switch (cmd) {
+
+ case SC_IRQ_INSTALL:
+
+ if(line_used(info->line))
+ return -EEXIST;
+
+ type = irq_type_convert((unsigned int)arg);
+
+ virq = mbkt_irq_map(info->hirq, type, info->line);
+ if (virq <= 0) {
+ pr_err("%s:mbkt_irq_map %d failed %d(%d)\n", __func__, info->line, virq, type);
+ return -ENOMEM;
+ }
+ /* pr_err("%s:mbkt_irq_map %d %d %d\n", __func__, info->line, virq, info->hirq);*/
+
+#if 1// niening_Test
+ /* if ( pinctrl_select_state(irq_ctx.pctrl, irq_ctx.state[info->line]) < 0) {
+ pr_err("%s:setting state%d failed\n", __func__, info->line);
+ return -ENODEV;
+ }
+*/
+ ret = request_irq(virq, mbtk_irq_isr, 0, info->name, info);
+ if(ret<0) {
+ pr_err("%s:request_irq %d failed %d\n", __func__, info->line, type);
+ return ret;
+ }
+#else
+ ret = devm_request_threaded_irq(g_MbtkPlatIrq_dev.dev, virq, mbtk_irq_isr,mbtk_irq_isr,0 , info->name, info);
+
+
+#endif
+ info->virq = virq;
+ info->type = type;
+
+ line_used(info->line) = 1;
+
+ pr_info("%s:install(%d) hirq(%d) virq(%d) type(%d)\n", __func__, info->line, info->hirq, info->virq, info->type);
+ break;
+
+ case SC_IRQ_UNINSTALL:
+
+
+ if(!line_used(info->line))
+ return -ENODEV;
+
+ irq_set_irq_type(info->virq, IRQ_TYPE_NONE);
+
+ free_irq(info->virq, info);
+
+ line_used(info->line) = 0;
+
+ pr_info("%s:uninstall(%d)\n", __func__, info->line);
+ break;
+
+ case SC_IRQ_SET_TYPE:
+
+ if(!line_used(info->line))
+ return -ENODEV;
+
+ type = irq_type_convert((unsigned int)arg);
+
+#if 0 //niening_test
+ ret = irq_set_irq_type(info->virq, type);
+#else
+
+ ret = irq_set_irq_type(info->virq, (type | IRQF_ONESHOT));
+#endif
+ if (ret)
+ return ret;
+
+ info->type = type;
+
+ pr_info("%s:set_type(%d) virq(%d) type(%d)\n", __func__, info->line, info->virq, info->type);
+
+ break;
+
+ case SC_IRQ_SET_WAKE:
+ if(!line_used(info->line))
+ return -ENODEV;
+
+ en = (unsigned int)arg;
+
+#if 0 //niening_test
+
+ ret = irq_set_irq_wake(info->virq, en);
+ if (ret)
+ return ret;
+#else
+ if(en)
+ enable_irq_wake(info->virq);
+ else
+ disable_irq_wake(info->virq);
+
+#endif
+
+ info->wake = en;
+ pr_info("%s:set_wake(%d) virq(%d) wake(%d)\n", __func__, info->line, info->virq, info->wake);
+
+ break;
+
+ case SC_IRQ_GET_WAKE:
+
+ if(!line_used(info->line))
+ return -ENODEV;
+ error = put_user(info->wake, (unsigned int __user *)arg);
+
+ pr_info("%s:get_wake(%d) virq(%d) wake(%d)\n", __func__, info->line, info->virq, info->wake);
+
+ break;
+
+
+ case SC_IRQ_GET_STATUS:
+ if(!line_used(info->line))
+ return -ENODEV;
+
+ mbtk_irq_wait(info->line);
+
+ spin_lock_irqsave(&irq_ctx.lock, flags);
+ error = put_user(irq_ctx.pending, (unsigned int __user *)arg);
+ spin_unlock_irqrestore(&irq_ctx.lock, flags);
+
+ pr_debug("%s:get_status(%d) virq(%d) wake(%d) pending(0x%x)\n",
+ __func__, info->line, info->virq, info->wake, irq_ctx.pending);
+
+ break;
+
+ case SC_IRQ_CLEAR_STATUS:
+ if(!line_used(info->line))
+ return -ENODEV;
+ spin_lock_irqsave(&irq_ctx.lock, flags);
+ irq_ctx.pending &= ~(1 << info->line);
+ spin_unlock_irqrestore(&irq_ctx.lock, flags);
+
+ pr_info("%s:clear_status(%d)\n", __func__, info->line);
+
+ break;
+
+ default:
+ error = -ENOTTY;
+ break;
+ }
+
+ return error;
+}
+
+#ifdef CONFIG_COMPAT
+
+static long
+mbtk_irq_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
+{
+ BUILD_BUG_ON(sizeof(loff_t) != sizeof(compat_loff_t));
+
+
+ if (_IOC_TYPE(cmd) != SC_IRQ_IOC_MAGIC)
+ return -ENOTTY;
+
+ if (_IOC_SIZE(cmd) == sizeof(compat_uptr_t)) {
+ cmd &= ~IOCSIZE_MASK;
+ cmd |= sizeof(char *) << IOCSIZE_SHIFT;
+ }
+
+ return mbtk_irq_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+
+#endif /* CONFIG_COMPAT */
+
+static const struct file_operations mbtk_plat_irq_fops = {
+ .open = mbtk_irq_open,
+ .release = mbtk_irq_release,
+ .llseek = no_llseek,
+ .unlocked_ioctl = mbtk_irq_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = mbtk_irq_compat_ioctl,
+#endif
+};
+
+static struct miscdevice mbtk_irq_device[MBTK_LIBIRQ_MAX] = {0};
+static int mbtk_plat_irq_device_init(struct platform_device *pdev)
+{
+ int i;
+ int ret = 0;
+ char name[16];
+ struct miscdevice *misc_dev = NULL;
+ struct device_node *np;
+ g_MbtkPlatIrq_dev.dev = &pdev->dev;
+
+
+ np = of_find_compatible_node(NULL, NULL, "mbtk,plat-irq");
+ if (NULL == np) {
+ pr_err("Can't find interrupt-controller \n");
+ return -ENODEV;
+ }
+ irq_ctx.np = np;
+
+ for(i= 0; i < MAX_GPIO_NUM; i++)
+ {
+ memset(name, 0, sizeof(name));
+ sprintf(name, "%s%d", "gpio_irq", i);
+ pr_err("%s. parse %s \n", __func__, name);
+
+ g_MbtkPlatIrq_dev.gpio_desc[i] = of_get_named_gpio(np, name, 0);
+ g_MbtkPlatIrq_dev.release_func_callback[i] = FALSE;
+
+ if (unlikely(g_MbtkPlatIrq_dev.gpio_desc[i] < 0))
+ {
+ pr_err("%s. parse %s failed\n", __func__, name);
+ }
+ else
+ {
+ pr_err("%s. %s=%d g_MbtkPlatIrq_dev.release_func_callback[i] =%d\n", __func__, name, g_MbtkPlatIrq_dev.gpio_desc[i], g_MbtkPlatIrq_dev.release_func_callback[i]);
+ }
+
+ ret = gpio_request(g_MbtkPlatIrq_dev.gpio_desc[i], name);
+ if(ret < 0)
+ {
+ pr_err("%s. gpio_request for =%d failed\n", __func__,g_MbtkPlatIrq_dev.gpio_desc[i]);
+ return ret;
+ }
+
+ gpio_direction_input(g_MbtkPlatIrq_dev.gpio_desc[i]);
+ }
+
+/*
+ irq_ctx.pctrl = devm_pinctrl_get(&pdev->dev);
+ if (IS_ERR(irq_ctx.pctrl)) {
+ dev_warn(&pdev->dev, "Failed to get sc_irq pins");
+ printk("--->%s/L%d\n", __FUNCTION__, __LINE__);
+ irq_ctx.pctrl = NULL;
+ return -ENODEV;
+ }
+*/
+ for (i=0; i<MBTK_LIBIRQ_MAX; i++) {
+ misc_dev = &mbtk_irq_device[i];
+ misc_dev->mode = 0666,
+ misc_dev->minor = MBTK_IRQ_MINOR + i,
+ memset(name, 0, sizeof(name));
+ sprintf(name, "%s%d", "sc_irq", i);
+ misc_dev->name = name;
+ misc_dev->fops = &mbtk_plat_irq_fops;
+
+ strcpy(irq_ctx.info[i].name, name);
+ irq_ctx.info[i].line = i;
+ irq_ctx.info[i].hirq = irq_line_convert(i);
+ init_waitqueue_head(&irq_ctx.info[i].wait);
+
+ while ((ret = misc_register(misc_dev)) < 0) {
+ if (ret != -EINTR)
+ break;
+ }
+ if (ret < 0) {
+
+ printk(KERN_ERR "misc_register failed with error %d\n", ret);
+ }
+
+
+ /* ret = misc_register(misc_dev);
+ if (ret) {
+ pr_err("%s:register dev(%d) failed:%d \n", __func__, i, ret);
+ return ret;
+ }*/
+
+#if 0 //niening_Test
+ irq_ctx.state[i] = pinctrl_lookup_state(irq_ctx.pctrl, name);
+ if (IS_ERR(irq_ctx.state[i])) {
+
+ dev_err(&pdev->dev, "TEST: missing state(%s)\n", name);
+ return -ENODEV;
+ }
+#endif
+ }
+
+
+ spin_lock_init(&irq_ctx.lock);
+
+ return ret;
+};
+
+static int mbtk_plat_irq_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ //ret = mbtk_plat_irq_device_init();
+ //if (ret)
+ // return ret;
+
+ ret = mbtk_plat_irq_device_init(pdev);
+
+ device_init_wakeup(&pdev->dev, true);
+
+ return ret;
+}
+
+static int mbtk_plat_irq_remove(struct platform_device *pdev)
+{
+ return 0;
+}
+
+static const struct of_device_id mbtk_plat_irq_match[] = {
+ { .compatible = "mbtk,plat-irq", },
+ { }
+};
+
+static struct platform_driver zx_bsp_driver = {
+ .probe = mbtk_plat_irq_probe,
+ .remove = mbtk_plat_irq_remove,
+ .driver = {
+ .name = "mbtk_PlatIrq",
+ .of_match_table = mbtk_plat_irq_match,
+ },
+};
+builtin_platform_driver(zx_bsp_driver)
+
+/*---------------------------------------------------------------*/
+#if 0
+
+static struct reset_control *reboot_rst;
+static int zx_restart(struct notifier_block *this,
+ unsigned long mode, void *cmd)
+{
+ if (reboot_rst) {
+ reset_control_assert(reboot_rst);
+ }
+
+ return NOTIFY_DONE;
+}
+
+static struct notifier_block zx_restart_handler = {
+ .notifier_call = zx_restart,
+ .priority = 129,
+};
+
+static int zx_reboot_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct device_node *np = pdev->dev.of_node;
+
+ reboot_rst = of_reset_control_get_by_index(np, 0);
+ if (!reboot_rst) {
+ dev_err(&pdev->dev, "No reset handler found!");
+ return -EINVAL;
+ }
+
+ ret = register_restart_handler(&zx_restart_handler);
+ if (ret)
+ pr_warn("cannot register restart handler, %d\n", ret);
+
+ return 0;
+}
+
+static const struct of_device_id zx_reboot_match[] = {
+ { .compatible = "zte,reboot", },
+ { }
+};
+
+static struct platform_driver zx_reboot_driver = {
+ .probe = zx_reboot_probe,
+ .driver = {
+ .name = "zx_reboot",
+ .of_match_table = zx_reboot_match,
+ },
+};
+builtin_platform_driver(zx_reboot_driver)
+
+/*----------------------------------------------------------------*/
+#define CONFIG_RPMSG_LOG 1
+
+#ifdef CONFIG_RPMSG_LOG
+#define RPMSG_LOG_SIZE (20*1024)
+static char rpmsg_printk_buf[RPMSG_LOG_SIZE];
+static u32 rpmsg_log_point = 0;
+static u32 rpmsg_log_turn = 0;
+static u32 rpmsg_sram_inited = 0;
+//static char rpmsg_log_temp_buf[512] = {0};
+static spinlock_t rpmsg_log_lock;
+
+static void rpmsg_sram_cpy(char *s, unsigned len)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rpmsg_log_lock, flags);
+
+ if(rpmsg_log_point + len + 2 >= RPMSG_LOG_SIZE) {
+ rpmsg_log_point = 0;
+
+ if (!rpmsg_log_turn)
+ rpmsg_log_turn = 1;
+ }
+
+ memcpy(rpmsg_printk_buf+rpmsg_log_point, s, len);
+ rpmsg_log_point += len;
+ rpmsg_printk_buf[rpmsg_log_point]=0;
+
+ spin_unlock_irqrestore(&rpmsg_log_lock, flags);
+}
+#endif
+
+static ssize_t rpmsg_log_show(struct kobject *kobj, struct kobj_attribute *attr,
+ char *buf)
+{
+ char *s = buf;
+
+#ifdef CONFIG_RPMSG_LOG
+ unsigned long flags;
+
+ if (rpmsg_sram_inited) {
+ spin_lock_irqsave(&rpmsg_log_lock, flags);
+
+ if (!rpmsg_log_turn) {
+ s += sprintf(s, "%s", rpmsg_printk_buf);
+ }
+ else {
+ s += sprintf(s, "%s", rpmsg_printk_buf+rpmsg_log_point+2);
+ s += sprintf(s, "%s", rpmsg_printk_buf);
+ }
+
+ spin_unlock_irqrestore(&rpmsg_log_lock, flags);
+ }
+#endif
+
+ return (s - buf);
+}
+
+/**
+ * usage: like printk(...)
+ */
+void rpmsg_printk(const char *fmt, ...)
+{
+#ifdef CONFIG_RPMSG_LOG
+ va_list args;
+ unsigned long long t;
+ unsigned long nanosec_rem;
+ int tlen, len;
+ char rpmsg_log_temp_buf[512] = {0};
+
+ if(!rpmsg_sram_inited)
+ return;
+
+ va_start(args, fmt);
+
+ /* add time stamp */
+ t = cpu_clock(smp_processor_id());
+ nanosec_rem = do_div(t, 1000000000);
+ tlen = sprintf(rpmsg_log_temp_buf, ">%5lu.%06lu< ",
+ (unsigned long) t, nanosec_rem / 1000);
+
+ len = vsprintf(rpmsg_log_temp_buf+tlen, fmt, args);
+ len += tlen;
+
+ rpmsg_sram_cpy(rpmsg_log_temp_buf, len);
+
+ va_end(args);
+#endif
+}
+
+void rpmsg_sram_init(void)
+{
+#ifdef CONFIG_RPMSG_LOG
+ pr_info("[RPMSG] LOG_INIT \n");
+
+ memset(rpmsg_printk_buf, 0, RPMSG_LOG_SIZE);
+ rpmsg_log_point = 0;
+
+ spin_lock_init(&rpmsg_log_lock);
+
+ rpmsg_sram_inited = 1;
+#endif
+}
+
+#endif
\ No newline at end of file