// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
/*
 * Copyright (c) 2019 Amlogic, Inc. All rights reserved.
 */

#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/types.h>
#include <linux/input.h>
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/mutex.h>
#include <linux/errno.h>
#include <asm/irq.h>
#include <linux/io.h>

#include <linux/major.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <linux/pinctrl/consumer.h>
#include <linux/of_platform.h>
#include <linux/of_address.h>
#include "meson_ir_core.h"
#include "meson_ir_main.h"

static void meson_ir_do_keyup(struct meson_ir_dev *dev)
{
	int cnt;
	struct meson_ir_chip *chip = (struct meson_ir_chip *)dev->platform_data;
	struct meson_ir_map_tab_list *ct = chip->cur_tab;

	if (!ct)
		return;

	if (DECIDE_VENDOR_TA_ID) {
		for (cnt = 0; cnt <= chip->input_cnt; cnt++) {
			if (chip->search_id[cnt] == ct->tab.vendor)
				break;
		}
		if (cnt > chip->input_cnt) {
			dev_err(chip->dev, "vendor ID Configuration error\n");
			dev_err(chip->dev, "vendor = %x, product = %x, version = %x\n",
					ct->tab.vendor, ct->tab.product, ct->tab.version);
			return;
		}
		input_report_key(dev->input_device_ots[cnt], dev->last_keycode, 0);
		input_sync(dev->input_device_ots[cnt]);
	} else {
		input_report_key(dev->input_device, dev->last_keycode, 0);
		input_sync(dev->input_device);
	}
	dev->keypressed = 0;
	dev->last_scancode = -1;
	meson_ir_dbg(dev, "keyup!!\n");
}

void meson_ir_timer_keyup(struct timer_list *t)
{
	struct meson_ir_dev *dev = from_timer(dev, t, timer_keyup);
	unsigned long flags;

	if (!dev->keypressed)
		return;
	spin_lock_irqsave(&dev->keylock, flags);
	if (dev->is_next_repeat(dev)) {
		dev->keyup_jiffies = jiffies +
			msecs_to_jiffies(dev->keyup_delay);
		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
		dev->wait_next_repeat = 1;
		meson_ir_dbg(dev, "wait for repeat\n");
	} else {
		if (time_is_before_eq_jiffies(dev->keyup_jiffies))
			meson_ir_do_keyup(dev);
		dev->wait_next_repeat = 0;
	}
	spin_unlock_irqrestore(&dev->keylock, flags);
}

static void meson_ir_do_keydown(struct meson_ir_dev *dev, int scancode,
				u32 keycode)
{
	int cnt;
	struct meson_ir_chip *chip = (struct meson_ir_chip *)dev->platform_data;
	struct meson_ir_map_tab_list *ct = chip->cur_tab;

	if (!ct)
		return;
	meson_ir_dbg(dev, "keypressed=0x%x\n", dev->keypressed);

	if (dev->keypressed)
		meson_ir_do_keyup(dev);

	if (keycode != KEY_RESERVED) {
		dev->keypressed = 1;
		dev->last_scancode = scancode;
		dev->last_keycode = keycode;
		if (DECIDE_VENDOR_TA_ID) {
			for (cnt = 0; cnt <= chip->input_cnt; cnt++) {
				if (chip->search_id[cnt] == ct->tab.vendor)
					break;
			}
			if (cnt > chip->input_cnt) {
				dev_err(chip->dev, "vendor ID configuration error\n");
				dev_err(chip->dev, "vendor = %x, product = %x, version = %x\n",
						ct->tab.vendor, ct->tab.product, ct->tab.version);
				return;
			}
			input_report_key(dev->input_device_ots[cnt], keycode, 1);
			input_sync(dev->input_device_ots[cnt]);
		} else {
			input_report_key(dev->input_device, keycode, 1);
			input_sync(dev->input_device);
		}
		meson_ir_dbg(dev, "report key!!\n");
	} else {
		dev_err(dev->dev, "no valid key to handle");
	}
}

void meson_ir_keydown(struct meson_ir_dev *dev, int scancode, int status)
{
	unsigned long flags;
	u32 keycode;

	if (dev->led_blink)
		led_trigger_blink_oneshot(dev->led_feedback, &dev->delay_on,
					  &dev->delay_off, 0);

	if (status != IR_STATUS_REPEAT) {
		if (dev->is_valid_custom && !dev->is_valid_custom(dev)) {
			dev_err(dev->dev, "invalid custom:0x%x\n",
				dev->cur_hardcode);
			return;
		}
	}
	spin_lock_irqsave(&dev->keylock, flags);
	/**
	 *only a few keys which be set in key map table support
	 *report relative axes event in mouse mode, other keys
	 *will continue to report key event.
	 */
	if (status == IR_STATUS_NORMAL || status == IR_STATUS_REPEAT) {
		/*to report relative axes event*/
		if (dev->report_rel(dev, scancode, status) == 0) {
			spin_unlock_irqrestore(&dev->keylock, flags);
			return;
		}
	}

	if (status == IR_STATUS_NORMAL) {
		keycode = dev->getkeycode(dev, scancode);
		if (keycode == KEY_POWER)
			pm_wakeup_event(dev->dev, 2000);
		meson_ir_do_keydown(dev, scancode, keycode);
	}

	if (dev->keypressed) {
		dev->wait_next_repeat = 0;
		dev->keyup_jiffies = jiffies +
			msecs_to_jiffies(dev->keyup_delay);
		mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
	}
	spin_unlock_irqrestore(&dev->keylock, flags);
}
EXPORT_SYMBOL(meson_ir_keydown);

void meson_ir_input_ots_configure(struct meson_ir_dev *dev, int cnt0,
				  struct ir_map_tab *ir_map)
{
	int i;

	for (i = 0; i < ir_map->map_size; i++)
		input_set_capability(dev->input_device_ots[cnt0], EV_KEY,
				     ir_map->codemap[i].map.keycode);
}
EXPORT_SYMBOL(meson_ir_input_ots_configure);

void meson_ir_input_configure(struct meson_ir_dev *dev,
			      struct ir_map_tab *ir_map)
{
	int i;

	for (i = 0; i < ir_map->map_size; i++)
		input_set_capability(dev->input_device, EV_KEY,
				     ir_map->codemap[i].map.keycode);
}
EXPORT_SYMBOL(meson_ir_input_configure);

void meson_ir_input_mouse_configure(struct meson_ir_dev *dev)
{
	int cnt;
	struct meson_ir_chip *chip = (struct meson_ir_chip *)dev->platform_data;

	for (cnt = 0; cnt <= chip->input_cnt; cnt++) {
		input_set_capability(dev->input_device_ots[cnt], EV_REL, REL_X);
		input_set_capability(dev->input_device_ots[cnt], EV_REL, REL_Y);
		input_set_capability(dev->input_device_ots[cnt], EV_REL, REL_WHEEL);
	}

	input_set_capability(dev->input_device, EV_REL, REL_X);
	input_set_capability(dev->input_device, EV_REL, REL_Y);
	input_set_capability(dev->input_device, EV_REL, REL_WHEEL);
}
EXPORT_SYMBOL(meson_ir_input_mouse_configure);
