/*
 *  Copyright (c) 1996-2007 Digi International Inc., All Rights Reserved
 *
 *  This software contains proprietary and confidential information of Digi
 *  International Inc.  By accepting transfer of this copy, Recipient agrees
 *  to retain this software in confidence, to prevent disclosure to others,
 *  and to make no use of this software other than that for which it was
 *  delivered.  This is an unpublished copyrighted work of Digi International
 *  Inc.  Except as permitted by federal law, 17 USC 117, copying is strictly
 *  prohibited.
 *
 *  Restricted Rights Legend
 *
 *  Use, duplication, or disclosure by the Government is subject to
 *  restrictions set forth in sub-paragraph (c)(1)(ii) of The Rights in
 *  Technical Data and Computer Software clause at DFARS 252.227-7031 or
 *  subparagraphs (c)(1) and (2) of the Commercial Computer Software -
 *  Restricted Rights at 48 CFR 52.227-19, as applicable.
 *
 *  Digi International Inc. 11001 Bren Road East, Minnetonka, MN 55343
 *
 *****************************************************************************
 *
 * This file contains an external GPIO driver. All APIs in this file are implemented
 * solely for external GPIO device.
 *
 */

 
 
/*ad*
 * This GPIO API driver allows user to configure, set and get gpio lines using 
 * functional name reference.  In the past, the NETOS GPIO APIs are configured,
 * set or get using hardware pin number.  This version of APIs provides a new set of 
 * functions that access GPIO control using functional names. i.e. GPIO_ERROR_LED, etc.
 *
 * This new APIs also support the configure and control of the external GPIO functions.
 * In the NS9360 Platform, depending on the type of the development board, there can
 * can two to four GPIO expander chips on board.  This driver is created to allow
 * user to have a standard interface to read or set a perticular GPIO pin in a
 * specific chip.  It is our intention that different kind of IO expender can be 
 * fit into the following APIs and to allow a more common and simple interface 
 * for user to access those external GPIO pins.
 *
 * @external
 * @category BSP:Device_Drivers:GPIOByFunctionNameDriver
 * @since 6.3
 * @include 	<nagpio.h>
 * @library 	bsp
 * @platform 	ns9360_a,connectcore9c_a,connectcorewi9c_a,connectcore9p9360_a
 * @overview Functional Name Based GPIO Driver
 *
*ad*/

#include "assert.h"
#include "nagpio.h"
#include "gpioplatform.h"
#include "processorgpio.h"
#include "bsp_sys.h"
#include "bsp_drivers.h"

#ifndef BOOT_LOADER
#if BSP_INCLUDE_I2C_EXPANDER
#include "i2c_gpio.h"
#endif
#else
#if (BSP_ENABLE_SLEEP_EXTERNAL_RESET == FALSE)
#define NA_GPIO_NOT_NEEDED
#endif
#endif

#ifndef NA_GPIO_NOT_NEEDED

/* A GPIO pin can have three states.  It can be an input, an output or an
 * interrupt.  The GpioSetInput, GpioSetOutput, GpioSetInterrupt functions
 * change the state of a single gpio pin.  When set to be an output, the
 * output value can be set with the GpioSetOutputValue function. The
 * current value of the pin can be read with GpioGetValue.
 */

/* Convert a function number to a gpio type, addr and pin. */
/* Returns TRUE if the function exists on the hardware, or FALSE if not. */
static int GpioFunction(int function, unsigned long *gpio_type, unsigned long *addr, unsigned long *gpio_pin)
{
    if (function < 0)
    {
        return GpioPlatformFunction(function, gpio_type, addr, gpio_pin);
    }
    *gpio_type = GPIO_TYPE_PROCESSOR_PIN;
    return ProcessorGpioPin(function, addr, gpio_pin);
}


/*ad*
 *  This returns TRUE if the specified function exists on the
 * hardware, or FALSE if not.
 *
 *
 * @external
 * @category BSP:Device_Drivers:GPIOByFunctionNameDriver
 * @since 6.3
 *
 * @param    function             functional name to be checked.
 *
 *
 * @return   1                    Success
 * @return   otherwise            Failure
 *
*ad*/
int naGpioFunctionExists(int function)
{
    unsigned long gpio_type;
    unsigned long addr;
    unsigned long gpio_pin;
    
    return GpioFunction(function, &gpio_type, &addr, &gpio_pin);
}


/*ad*
 *  Set the multiplexing of this GPIO pin to be a general purpose input pin.
 *
 *
 * @external
 * @category BSP:Device_Drivers:GPIOByFunctionNameDriver
 * @since 6.3
 *
 * @param    function             GPIO functional channel to be configured
 *
 * 
 * @return   1                    Success
 * @return   otherwise            Failure
 * 
 * @note    Before calling this API, if I2C GPIO devices are used, be sure that the 
 *          function NAI2CInit() has been called to initialize the I2C Master.
*ad*/

int naGpioSetInput(int function)
{
    unsigned long gpio_type;
    unsigned long addr;
    unsigned long gpio_pin;
    
    if (GpioFunction(function, &gpio_type, &addr, &gpio_pin))
    {
        switch (gpio_type)
        {
            case GPIO_TYPE_PROCESSOR_PIN:
                return ProcessorGpioSetInput(addr, gpio_pin);
#ifndef BOOT_LOADER
#if BSP_INCLUDE_I2C_EXPANDER
            case GPIO_TYPE_I2C:
                return I2CGpioSetInput(addr, gpio_pin);
#endif
#endif
            default:
                break;
        }
    }
    return -1;
}


/*ad*
 *  Set the multiplexing of this GPIO pin to be a general purpose output pin.
 *
 *
 * @external
 * @category BSP:Device_Drivers:GPIOByFunctionNameDriver
 * @since 6.3
 *
 * @param    function             GPIO functional channel to be configured
 * @param	 default_value        Initial state of GPIO pin - ON or OFF - after it is configured
 *                                as an output pin.
 *
 *
 * @return   1                    Success
 * @return   otherwise            Failure
 *
 * @note    Before calling this API, if I2C GPIO devices are used, be sure that the 
 *          function NAI2CInit() has been called to initialize the I2C Master.
*ad*/

int naGpioSetOutput(int function, unsigned int default_value)
{
    unsigned long gpio_type;
    unsigned long addr;
    unsigned long gpio_pin;
    
    if (GpioFunction(function, &gpio_type, &addr, &gpio_pin))
    {
        switch (gpio_type)
        {
	        case GPIO_TYPE_PROCESSOR_PIN:
                return ProcessorGpioSetOutput(addr, gpio_pin, default_value);
#ifndef BOOT_LOADER
#if BSP_INCLUDE_I2C_EXPANDER
            case GPIO_TYPE_I2C:
                return I2CGpioSetOutput(addr, gpio_pin, default_value);
#endif
#endif
            default:
                break;
        }
    }
    return -1;
}

#ifndef BOOT_LOADER
/* Set this gpio pin to be an interrupt.
 * level is 1 for high, 0 for low.
 * edge_trigger is 1 for edge-triggered, 0 for level-triggered.
 * This function will set up processor registers to make the pin an interrupt
 * source.  The caller must separately call operating system functions
 * to register an interrupt handler and enable the interrupt.
 * This function returns the interrupt source index of the interrupt.
 * It returns -1 if the gpio pin cannot be an interrupt source.
 */



/*ad*
 * Set this GPIO pin to be an interrupt.
 * This function will set up processor registers to make the pin an interrupt
 * source.  The caller must separately call operating system functions
 * to register an interrupt handler and enable the interrupt.
 *
 *
 *
 * @external
 * @category BSP:Device_Drivers:GPIOByFunctionNameDriver
 * @since 6.3
 *
 * @param    function             GPIO functional channel to be configured
 * @param    level                1 for high and 0 for low.
 * @param    edge_trigger         1 for edge-triggered, 0 for level-triggered.
 *
 * @return   1                    Success
 * @return   otherwise            Failure
 *
*ad*/

int naGpioSetInterrupt(int function, int level, int edge_trigger)
{
    unsigned long gpio_type;
    unsigned long addr;
    unsigned long gpio_pin;
    
    if (GpioFunction(function, &gpio_type, &addr, &gpio_pin))
    {
        switch (gpio_type)
        {
            case GPIO_TYPE_PROCESSOR_PIN:
                return ProcessorGpioSetInterrupt(addr, gpio_pin, level, edge_trigger);
#ifndef BOOT_LOADER
#if BSP_INCLUDE_I2C_EXPANDER
            case GPIO_TYPE_I2C:
                return I2CGpioSetInterrupt(addr, gpio_pin, level, edge_trigger);
#endif
#endif
            default:
                NA_ASSERT(0);
            break;
        }
    }
    return -1;
}
#endif /* !BOOT_LOADER */


/*ad*
 * Returns the logic level of a GPIO input pin.
 *
 * @external
 * @category BSP:Device_Drivers:GPIOByFunctionNameDriver
 * @since 6.3
 *
 * @param    function             GPIO functional channel of the GPIO line
 *
 * @return   0 or non-zero        logic value of the GPIO line.  (Non-zero is logic one.)
 *
 * @note    Before calling this API, if I2C GPIO devices are used, be sure that the 
 *          function NAI2CInit() has been called to initialize the I2C Master.
*ad*/

unsigned long naGpioGetValue(int function)
{
    unsigned long gpio_type;
    unsigned long addr;
    unsigned long gpio_pin;
#ifndef BOOT_LOADER
#if BSP_INCLUDE_I2C_EXPANDER    
    char gpio_value;
    int ret;
#endif
#endif
    
    if (GpioFunction(function, &gpio_type, &addr, &gpio_pin))
    {
        switch (gpio_type)
        {
            case GPIO_TYPE_PROCESSOR_PIN:
                return ProcessorGpioGetValue(addr, gpio_pin);
#ifndef BOOT_LOADER
#if BSP_INCLUDE_I2C_EXPANDER
            case GPIO_TYPE_I2C:
                ret = I2CGpioGetValue(addr, gpio_pin, &gpio_value);
                if (ret)
                    return gpio_value;
                else
                {
                    NA_ASSERT(0);
                    break;
                }
#endif
#endif
            default:
                NA_ASSERT(0);
                break;
        }
    }
    
    return (unsigned long)-1;
}

/* GPIO pin will be set based on value being 0 or non-zero.  Will have no effect
 * if pin is set as input or interrupt.
 */

/*ad*
 * Sets the logic level of the GPIO output function pin at the processor output.
 *
 * @external
 * @category BSP:Device_Drivers:GPIOByFunctionNameDriver
 * @since 6.3
 *
 * @param    function             GPIO functional channel of the GPIO line
 * @param    value                Logic level of the GPIO pin
 *
 * @return   1                    Success
 * @return   otherwise            Failure
 *
 *
 * @note    Before calling this API, if I2C GPIO devices are used, be sure that the 
 *          function NAI2CInit() has been called to initialize the I2C Master.
 *
*ad*/
int naGpioSetOutputValue(int function, unsigned long value)
{
    unsigned long gpio_type;
    unsigned long addr;
    unsigned long gpio_pin;
    
    if (GpioFunction(function, &gpio_type, &addr, &gpio_pin))
    {
        switch (gpio_type)
        {
            case GPIO_TYPE_PROCESSOR_PIN:
                return ProcessorGpioSetOutputValue(addr, gpio_pin, value);
#ifndef BOOT_LOADER
#if BSP_INCLUDE_I2C_EXPANDER
            case GPIO_TYPE_I2C:
                return I2CGpioSetOutputValue(addr, gpio_pin, value);
#endif
#endif
            default:
                break;
        }
    }
    return -1;
}

/* GPIO pin will be set to an output with an initial value based on value being
 * 0 or non-zero.  Will atomically change to an output with the desired value
 * if possible.  This attempts to avoid a glitch as the pin becomes an output.
 *
 * Obsoletes GpioSetOutput.
 */
int naGpioSetOutputWithValue(int function, unsigned long value)
{
    return (naGpioSetOutputValue(function, value));
}


#ifdef BSP_ARM9
int naGpioGetAddress(int function, unsigned long *addr, unsigned long *pin)
{
    unsigned long gpio_type;
    
    if (GpioFunction(function, &gpio_type, addr, pin))
    {
        switch (gpio_type)
        {
            case GPIO_TYPE_PROCESSOR_PIN:
                return ProcessorGpioGetAddress(addr, pin);
            
            default:
                break;
        }
    }
    return FALSE;
}

#if PROCESSOR == ns9210 || PROCESSOR == ns9215
/* Set a gpio pin to a particular function in the gpio mux.  This is only really
 * useful for processor gpio pins, but calling this function abstracts processor
 * differences.
 * Returns TRUE if successful, or FALSE otherwise.
 */
int naGpioSetFunction(int function, int gpio_function)
{
    unsigned long gpio_type;
    unsigned long addr;
    unsigned long gpio_pin;
    
    if (GpioFunction(function, &gpio_type, &addr, &gpio_pin))
    {
	switch (gpio_type)
	{
	    case GPIO_TYPE_PROCESSOR_PIN:
		return ProcessorGpioSetFunction(addr, gpio_pin, gpio_function);
	    default:
		break;
	}
    }
    return 0;
}
#endif

#endif
#endif /* NA_GPIO_NOT_NEEDED */

