/*
 * Copyright 2023 Sony Corporation
 */

#include "sony_panel_oled.h"

#include <dm/device.h>
#include <dm/uclass.h>
#include <linux/delay.h>
#include <pwm.h>
#include <stdio.h>
#include <utility.h>

#include "mtk_pnl_out_if.h"

int panel_oledPanelControl(void)
{
	int ret;
	ofnode base_node;
	ofnode node;
	uint32_t out_byte_mode;
	uint32_t out_byte_mode_reg_addr;
	uint32_t out_byte_mode_reg_mask_st;
	uint32_t out_byte_mode_reg_mask_ed;

	base_node = ofnode_by_compatible(ofnode_null(), "sony,paneldet");
	node = ofnode_by_compatible(base_node, "sony,oled_panel_control");
	if (!ofnode_valid(node))
		return 0;	// do oled panel control only when dts has compatible property

	ret = ofnode_read_u32(node, "panel_out_byte_mode", &out_byte_mode);
	if (ret != 0) {
		printf("%s: Fail to get [out_byte_mode]!!!!!\n", __func__);
		return -1;
	}
	if (out_byte_mode == 1) {
		ret = ofnode_read_u32(node, "panel_out_byte_mode_reg_addr", &out_byte_mode_reg_addr);
		if (ret != 0) {
			printf("%s: Fail to get [out_byte_mode_reg_addr]!!!!!\n", __func__);
			return -1;
		}
		ret = ofnode_read_u32(node, "panel_out_byte_mode_reg_mask_st", &out_byte_mode_reg_mask_st);
		if (ret != 0) {
			printf("%s: Fail to get [out_byte_mode_reg_mask_st]!!!!!\n", __func__);
			return -1;
		}
		ret = ofnode_read_u32(node, "panel_out_byte_mode_reg_mask_ed", &out_byte_mode_reg_mask_ed);
		if (ret != 0) {
			printf("%s: Fail to get [out_byte_mode_reg_mask_ed]!!!!!\n", __func__);
			return -1;
		}

		mtk_pnl_oledip_write(NULL, out_byte_mode_reg_addr, 1, (uint8_t)out_byte_mode_reg_mask_st, (uint8_t)out_byte_mode_reg_mask_ed);
		//Debug
		// printf("%s: reg_addr=0x%x, reg_mask_st=%d, reg_mask_ed=%d\n", __func__, out_byte_mode_reg_addr, out_byte_mode_reg_mask_st, out_byte_mode_reg_mask_ed);
	}

	return 0;
}


int panel_oledLogoBrightnessControl(void)
{
	int ret;
	ofnode base_node;
	ofnode node;
	uint32_t brightness;
	uint32_t reg_addr;
	uint32_t reg_mask_st;
	uint32_t reg_mask_ed;

	if (pm_check_back_ground_active() != 0)
		return 0;	// On Panel off boot, brightness control is not performed

	base_node = ofnode_by_compatible(ofnode_null(), "sony,paneldet");
	node = ofnode_by_compatible(base_node, "sony,oled_logo_brightness");
	if (!ofnode_valid(node))
		return 0;	// do brightness control only when dts has compatible property

	ret = ofnode_read_u32(node, "brightness", &brightness);
	if (ret != 0) {
		printf("%s: Fail to get [brightness]!!!!!\n", __func__);
		return -1;
	}
	ret = ofnode_read_u32(node, "reg_addr", &reg_addr);
	if (ret != 0) {
		printf("%s: Fail to get [reg_addr]!!!!!\n", __func__);
		return -1;
	}
	ret = ofnode_read_u32(node, "reg_mask_st", &reg_mask_st);
	if (ret != 0) {
		printf("%s: Fail to get [reg_mask_st]!!!!!\n", __func__);
		return -1;
	}
	ret = ofnode_read_u32(node, "reg_mask_ed", &reg_mask_ed);
	if (ret != 0) {
		printf("%s: Fail to get [reg_mask_ed]!!!!!\n", __func__);
		return -1;
	}

	mtk_pnl_oledip_write(NULL, reg_addr, brightness, (uint8_t)reg_mask_st, (uint8_t)reg_mask_ed);
	//Debug
	// printf("%s: reg_addr=0x%x, birghtness=%d, reg_mask_st=%d, reg_mask_ed=%d\n", __func__, reg_addr, brightness, reg_mask_st, reg_mask_ed);

	return 0;
}

int panel_oledEvddControl(void)
{
	int ret;
	ofnode base_node;
	ofnode node;
	struct udevice *pwm;
	uint32_t chip;
	uint32_t channel;
	uint32_t period;
	uint32_t duty;
	uint32_t invert;
	uint32_t post_delay_ms;

	base_node = ofnode_by_compatible(ofnode_null(), "sony,paneldet");
	node = ofnode_by_compatible(base_node, "sony,oled_evdd_pwm");
	if (!ofnode_valid(node))
		return 0;	// do evdd control only when dts has compatible property

	ret = ofnode_read_u32(node, "pwm_chip", &chip);
	if (ret != 0) {
		printf("%s: Fail to get [pwm_chip]!!!!!\n", __func__);
		return -1;
	}
	ret = ofnode_read_u32(node, "pwm_channel", &channel);
	if (ret != 0) {
		printf("%s: Fail to get [pwm_channel]!!!!!\n", __func__);
		return -1;
	}
	ret = ofnode_read_u32(node, "pwm_period", &period);
	if (ret != 0) {
		printf("%s: Fail to get [pwm_period]!!!!!\n", __func__);
		return -1;
	}
	ret = ofnode_read_u32(node, "pwm_duty", &duty);
	if (ret != 0) {
		printf("%s: Fail to get [pwm_duty]!!!!!\n", __func__);
		return -1;
	}
	ret = ofnode_read_u32(node, "pwm_invert", &invert);
	if (ret != 0) {
		printf("%s: Fail to get [pwm_invert]!!!!!\n", __func__);
		return -1;
	}
	ret = ofnode_read_u32(node, "post_delay_ms", &post_delay_ms);
	if (ret != 0) {
		printf("%s: Fail to get [post_delay_ms]!!!!!\n", __func__);
		return -1;
	}

	ret = uclass_get_device(UCLASS_PWM, chip, &pwm);
	if (ret != 0) {
		printf("%s: Fail to get PWM device !!!!!\n", __func__);
		return ret;
	}
	ret = pwm_set_config(pwm, channel, period, duty);
	if (ret != 0) {
		printf("%s: Fail to set PWM config !!!!!\n", __func__);
		return ret;
	}
	ret = pwm_set_invert(pwm, channel, (bool)invert);
	if (ret != 0) {
		printf("%s: Fail to set PWM invert setting !!!!!\n", __func__);
		return ret;
	}
	ret = pwm_set_enable(pwm, channel, true);
	if (ret != 0) {
		printf("%s: Fail to enable PWM !!!!!\n", __func__);
		return ret;
	}

	// Wait to satisfy the constraint that there must be a gap between EVDD Control and BL_ON
	mdelay(post_delay_ms);

	//Debug
	// printf("%s: chip=0x%x, channel=%d, period=%d, duty=%d, invert=%d, post_delay=%d\n", __func__, chip, channel, period, duty, invert, post_delay_ms);

	return 0;
}
