/*
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

/***
 * \file: bluetooth.c
 * 
 * \brief: Bluetooth chip access routine.
 *
 */

#include "stdio.h"
#include "uart.h"
#include "bluetooth.h"
#include "gpio.h"
#include "dm8127_platform.h"
#include "ioexpander.h"
#include "dm8127_types.h"
#include "dm8127_evm.h"
#include "dm8127_i2c.h"

#include "dm8127_uart.h"

#define UART_TIMEOUT            (0x80000)
#define IOEXP_BT_EN_GPIO			(30u)

#ifdef NO_LONGER_VALID
/* 
 *
 *  BT Chip is connected to DM8127 through UART3.
 * 
 *  To BT to work on DM8127 EVM:
 *    1) IR Must be turned off.
 *       (Which means that IR and BT cannot co-exist)
 *       IR can be turned off through an IO Expander
 *       chip on the base board (slave address 0x20)
 * 
 *    2) UART3 Signals on IOEXPANSION board is controlled
 *       through a switch. The switch is controlled
 *       by UART3_SEL signal.
 * 
 *       This Signal can be controlled by driving 
 *       PIN 8 of the I2C IO Expander on IOEXPANSION LOW
 *       (slave address 0x21)
 */ 

SINT32 turnoff_irreciever
(
	void
)
{
	SINT32 retval;
#ifdef IIC
	 /* I2C0 and IO expander with slave address of 0x20 (Found on Base Board) */
	retval = i2cIoExpInit (0x0, 0x20);
	if (retval != SUCCESS)
	{
		printf ("Unable to initialize the IO Expander on the base board.\r\n");
		return (retval);
	}
	
	/* Driving pin 14 high on IO expander found on base board to turn off IR */
	/* Pins of IO expander starts from 0 */
	retval = i2c0IoExpStatusBitSet(0x0, 0x20, 14, 1);
#endif

	/* Bluetooth device interrupt  enable  */ // Need to check
	set_gpio_bank1 (8, 1);
	return retval;
}

SINT32 enable_btuart(void)
{
	SINT32 retval;
	
#ifdef IIC
	/* I2C0 and IO expander with slave address of 0x21 (Found on IOEXPANSION) */
	retval = i2cIoExpInit (0x0, 0x21);
	if (retval != SUCCESS)
	{
		printf ("Unable to initialize the IO Expander on the VCAM Board.\r\n");
		return (retval);
	}
	
	retval = i2c0IoExpStatusBitSet(0x0, 0x21, 4, 0); /* Drive UART3_SEL Low */
	retval = i2c0IoExpStatusBitSet(0x0, 0x21, 5, 0);
#endif


#if 0

	/* Need to check */
	set_gpio_bank0 (4, 0);
	set_gpio_bank0 (5, 0);
#endif

	if (retval != SUCCESS)
	{
		printf ("Unable to initialize the BT UART on DM8127 Board.\r\n");
		return (retval);
	}
return retval;
}

/**
 *\brief : GPIO bank 0's register pin handler.
 *
 *         This routine take the pin number and the status for the next
 *         action, i.e Enable or Disable.
 *
 *         This function initialize the GPIO bank 0.
 *
 *@param : gpio  [IN]  bit number for bank 0.
 *@param   value [IN]  current value to be modified.
 */

int set_gpio_bank0
(
	int gpio,
	int value
)
{
	unsigned int regval;
	static int initialised = 0;
		
	if (!initialised) {
	/* Reset GPIO Subsystem */
		GPIO0_SYSCONFIG = 0x00000020; /* Software Reset */
		delay(0x90000);
		GPIO0_SYSCONFIG = 0x100; /* no-idle */
		initialised = 1;
	}
	
	/* Output Enable GPIO16 in Bank 1 */		 
	regval = GPIO0_OE;
	regval = regval & ~(1 << gpio);  
	GPIO0_OE = regval;

	if (!value) {
		/* Set WLAN_ENABLE Low */
		regval = GPIO0_DATAOUT;
		regval = regval & ~(1 << gpio);
		GPIO0_DATAOUT = regval;
		regval = GPIO0_SETDATAOUT;
		regval = regval & ~(1 << gpio);
		GPIO0_SETDATAOUT = regval;
	} else {
		/* Set BT_ENABLE High */
		GPIO0_DATAOUT |= (1 <<  gpio);
		GPIO0_SETDATAOUT |= (1 << gpio);
	}
	
	return 0;
}

/**
 *\brief : GPIO bank 1's register pin handler.
 *
 *         This routine take the pin number and the status for the next
 *         action, i.e Enable or Disable.
 *
 *         This function initialize the GPIO bank 1.
 *
 *@param : gpio  [IN]  bit number for bank 1.
 *@param   value [IN]  current value to be modified.
 */


int set_gpio_bank1
(
	int gpio,
	int value
)
{
	unsigned int regval;
	static int initialised = 0;

	if (!initialised) {
	/* Reset GPIO Subsystem */
		GPIO1_SYSCONFIG = 0x00000020; /* Software Reset */
		delay(0x90000);
		GPIO1_SYSCONFIG = 0x100; /* no-idle */
		initialised = 1;
	}

	/* Output Enable GPIO16 in Bank 1 */
	regval = GPIO0_OE;
	regval = regval & ~(1 << gpio);
	GPIO0_OE = regval;

	if (!value) {
		/* Set WLAN_ENABLE Low */
		regval = GPIO0_DATAOUT;
		regval = regval & ~(1 << gpio);
		GPIO1_DATAOUT = regval;
		regval = GPIO1_SETDATAOUT;
		regval = regval & ~(1 << gpio);
		GPIO1_SETDATAOUT = regval;
	} else {
		/* Set BT_ENABLE High */
		GPIO1_DATAOUT |= (1 <<  gpio);
		GPIO1_SETDATAOUT |= (1 << gpio);
	}

	return 0;
}
#endif

/***
 * \brief : Bluetooth gpio initializer routine.
 *
 * \param : VOID
 * \return: SUCCESS
 */
int DM8127_evm_bt_init
(
	void
)
{

#if 0
	retval = turnoff_irreciever();
	if (retval != SUCCESS)
		return retval;
	
	retval = enable_btuart();
	if (retval != SUCCESS)
		return retval;
#endif
	/* Enable BT Chip */

	/* A arbitary huge delay to make sure BT chip is enabled */
	set_gpio_bank0 (IOEXP_BT_EN_GPIO, 1);
	delay(190000);
	set_gpio_bank0 (IOEXP_BT_EN_GPIO, 0);
	delay(190000);
	set_gpio_bank0 (IOEXP_BT_EN_GPIO, 1);
	delay(90000); /* settle down */
		
	return SUCCESS;
}

/* Send a HCI command over uart */
/***
 * \brief: HCI command handler.
 *
 * \param: handle [IN] BT UART handler
 * \n      cmd    [IN] future use
 * \n      opcode [IN] opcede to be sent
 * \n      len    [IN] lengthe of the opcode
 *
 * \return: 0 on success
 * \n       1 failed to send
 */
int send_hci_cmd
(
	UART_Handle handle,
	unsigned char cmd,
	unsigned int opcode,
	unsigned char *data,
	int len
)
{
        int err;
        /* sanity check */
        if (!handle || (data == INIT_VAL && len > 0))
                return -1;

		err = uart_send (handle, HCI_CMD_PKT, UART_TIMEOUT);
        if (err)
                goto failed_to_send;
        err = uart_send (handle, opcode & 0xff, UART_TIMEOUT);
        if (err)
                goto failed_to_send;
                
        err = uart_send (handle, (opcode >> 8) & 0xff, UART_TIMEOUT);
        if (err)
                goto failed_to_send;

        err = uart_send (handle, len, UART_TIMEOUT);
        if (err)
                goto failed_to_send;

        while(len-- > 0 && data) {
                err = uart_send(handle, *data, UART_TIMEOUT);
                if (err)
                        goto failed_to_send;

                data++;
        }

        return 0;

failed_to_send:
        return 1;
}

/***
 * \brief: routine to get the chip version from the Bluetooth device.
 *
 * \b \Descr: This function sends the set of command to the bluetooth chip
 * \n         to get the chip version.
 *
 * \param: handle [IN]  Bluetooth Uart handler
 * \n      manfid [OUT] pointer to get the version of BT chip
 *
 * \return: SUCCESS This function send success everytime.
 */

SINT32 get_btchip_version
(
	UART_Handle handle,
	UINT32 * manfid
)
{
	SINT32 err;
	char resp[255];
	char plen;
	char opcode[2];
    char status;
	SINT32 i;
	
	/* READ LOCAL VERSION of the BT Chip */
	err = send_hci_cmd(handle, HCI_CMD_PKT, HCI_READ_LOCAL_VER_CMD, INIT_VAL, 0);
	if (err)
		goto hci_cmd_send_err;
	
	err = uart_recv(handle, resp, UART_TIMEOUT);
	if (err)
		return err;

	if (resp[0] != HCI_EVENT_PKT)
		goto recvd_unknown_pkt;

	err = uart_recv(handle, resp, UART_TIMEOUT);
	if (err)
		goto recv_err;

 	if (resp[0] != COMMAND_COMPLETE_EVENT)
		goto err_cc_evnt;

	err = uart_recv(handle, &plen, UART_TIMEOUT);
	if (err)
		goto recv_err;

	err = uart_recv(handle, resp, UART_TIMEOUT);
	if (err)
		goto recv_err;

	if (resp[0] != HCI_CMD_PKT) /* Is event packet in response to CMD packet */
		goto recv_err;

	err = uart_recv(handle, &opcode[0], UART_TIMEOUT);
	if (err)
		goto recv_err;

	err = uart_recv(handle, &opcode[1], UART_TIMEOUT);
	if (err)
		goto recv_err;

#if 0
	/* Is event packet generated for RESET Command? */
	if (opcode != HCI_CMD_MANFID_OPCODE)
		goto recv_err;
#endif

	err = uart_recv(handle, &status, UART_TIMEOUT);
	if (err)
		goto recv_err;

	if (status != 0x0)
		goto recv_err;

	plen = plen - 4;
        
	for (i = 0; i < plen && i < 255; i++) {
		err = uart_recv(handle, &resp[i], UART_TIMEOUT);
		if (err)
        	goto recv_err;
	}
	
	*manfid = (resp[5] >> 8) | resp[4]; 	
		
	return SUCCESS;

err_cc_evnt:        
recvd_unknown_pkt:
hci_cmd_send_err:
recv_err:
        return FAILED;
}
