danube_led cleanup
SVN-Revision: 9757
This commit is contained in:
parent
a9fa8faa4c
commit
c47fa67cfb
3 changed files with 125 additions and 664 deletions
|
@ -42,7 +42,7 @@ CONFIG_CPU_SUPPORTS_HIGHMEM=y
|
||||||
CONFIG_DANUBE=y
|
CONFIG_DANUBE=y
|
||||||
CONFIG_DANUBE_ASC_UART=y
|
CONFIG_DANUBE_ASC_UART=y
|
||||||
CONFIG_DANUBE_GPIO=y
|
CONFIG_DANUBE_GPIO=y
|
||||||
# CONFIG_DANUBE_LED is not set
|
CONFIG_DANUBE_LED=y
|
||||||
CONFIG_DANUBE_MII0=y
|
CONFIG_DANUBE_MII0=y
|
||||||
CONFIG_DANUBE_MII1=y
|
CONFIG_DANUBE_MII1=y
|
||||||
CONFIG_DANUBE_WDT=y
|
CONFIG_DANUBE_WDT=y
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
#include <linux/errno.h>
|
#include <linux/errno.h>
|
||||||
#include <asm/danube/danube.h>
|
#include <asm/danube/danube.h>
|
||||||
#include <asm/danube/danube_gpio.h>
|
#include <asm/danube/danube_gpio.h>
|
||||||
#include <asm/danube/danube_gptu.h>
|
|
||||||
|
|
||||||
#define LED_CONFIG 0x01
|
#define LED_CONFIG 0x01
|
||||||
|
|
||||||
|
@ -45,38 +44,8 @@
|
||||||
#define CONFIG_OPERATION_MIPS0_ACCESS 0x0100
|
#define CONFIG_OPERATION_MIPS0_ACCESS 0x0100
|
||||||
#define CONFIG_DATA_CLOCK_EDGE 0x0200
|
#define CONFIG_DATA_CLOCK_EDGE 0x0200
|
||||||
|
|
||||||
|
#define DANUBE_LED_CLK_EDGE DANUBE_LED_FALLING
|
||||||
/*
|
//#define DANUBE_LED_CLK_EDGE DANUBE_LED_RISING
|
||||||
* Data Type Used to Call ioctl
|
|
||||||
*/
|
|
||||||
struct led_config_param {
|
|
||||||
unsigned long operation_mask; // Select operations to be performed
|
|
||||||
unsigned long led; // LED to change update source (LED or ADSL)
|
|
||||||
unsigned long source; // Corresponding update source (LED or ADSL)
|
|
||||||
unsigned long blink_mask; // LEDs to set blink mode
|
|
||||||
unsigned long blink; // Set to blink mode or normal mode
|
|
||||||
unsigned long update_clock; // Select the source of update clock
|
|
||||||
unsigned long fpid; // If FPI is the source of update clock, set the divider
|
|
||||||
// else if GPT is the source, set the frequency
|
|
||||||
unsigned long store_mode; // Set clock mode or single pulse mode for store signal
|
|
||||||
unsigned long fpis; // FPI is the source of shift clock, set the divider
|
|
||||||
unsigned long data_offset; // Set cycles to be inserted before data is transmitted
|
|
||||||
unsigned long number_of_enabled_led; // Total number of LED to be enabled
|
|
||||||
unsigned long data_mask; // LEDs to set value
|
|
||||||
unsigned long data; // Corresponding value
|
|
||||||
unsigned long mips0_access_mask; // LEDs to set access right
|
|
||||||
unsigned long mips0_access; // 1: the corresponding data is output from MIPS0, 0: MIPS1
|
|
||||||
unsigned long f_data_clock_on_rising; // 1: data clock on rising edge, 0: data clock on falling edge
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
extern int danube_led_set_blink(unsigned int, unsigned int);
|
|
||||||
extern int danube_led_set_data(unsigned int, unsigned int);
|
|
||||||
extern int danube_led_config(struct led_config_param *);
|
|
||||||
|
|
||||||
#define DATA_CLOCKING_EDGE FALLING_EDGE
|
|
||||||
#define RISING_EDGE 0
|
|
||||||
#define FALLING_EDGE 1
|
|
||||||
|
|
||||||
#define LED_SH_PORT 0
|
#define LED_SH_PORT 0
|
||||||
#define LED_SH_PIN 4
|
#define LED_SH_PIN 4
|
||||||
|
@ -228,691 +197,164 @@ extern int danube_led_config(struct led_config_param *);
|
||||||
|
|
||||||
#define SET_BITS(x, msb, lsb, value) (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
|
#define SET_BITS(x, msb, lsb, value) (((x) & ~(((1 << ((msb) + 1)) - 1) ^ ((1 << (lsb)) - 1))) | (((value) & ((1 << (1 + (msb) - (lsb))) - 1)) << (lsb)))
|
||||||
|
|
||||||
static struct semaphore led_sem;
|
static int danube_led_major;
|
||||||
|
|
||||||
static unsigned long gpt_on = 0;
|
static int
|
||||||
static unsigned long gpt_freq = 0;
|
danube_led_setup_gpio (void)
|
||||||
|
|
||||||
static unsigned long adsl_on = 0;
|
|
||||||
static unsigned long f_led_on = 0;
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
update_led (void)
|
|
||||||
{
|
{
|
||||||
int i, j;
|
/*
|
||||||
|
* Set LED_ST
|
||||||
|
* I don't check the return value, because I'm sure the value is valid
|
||||||
|
* and the pins are reserved already.
|
||||||
|
*/
|
||||||
|
LED_ST_ALTSEL0_SETUP(LED_ST_PORT, LED_ST_PIN);
|
||||||
|
LED_ST_ALTSEL1_SETUP(LED_ST_PORT, LED_ST_PIN);
|
||||||
|
LED_ST_DIR_SETUP(LED_ST_PORT, LED_ST_PIN);
|
||||||
|
LED_ST_OPENDRAIN_SETUP(LED_ST_PORT, LED_ST_PIN);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* GPT2 or FPID is the clock to update LEDs automatically.
|
* Set LED_D
|
||||||
*/
|
*/
|
||||||
if (readl(DANUBE_LED_CON1) >> 30)
|
LED_D_ALTSEL0_SETUP(LED_D_PORT, LED_D_PIN);
|
||||||
return 0;
|
LED_D_ALTSEL1_SETUP(LED_D_PORT, LED_D_PIN);
|
||||||
|
LED_D_DIR_SETUP(LED_D_PORT, LED_D_PIN);
|
||||||
|
LED_D_OPENDRAIN_SETUP(LED_D_PORT, LED_D_PIN);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check the status to prevent conflict of two consecutive update
|
* Set LED_SH
|
||||||
*/
|
*/
|
||||||
for ( i = 100000; i != 0; i -= j / 16 )
|
LED_SH_ALTSEL0_SETUP(LED_SH_PORT, LED_SH_PIN);
|
||||||
{
|
LED_SH_ALTSEL1_SETUP(LED_SH_PORT, LED_SH_PIN);
|
||||||
down(&led_sem);
|
LED_SH_DIR_SETUP(LED_SH_PORT, LED_SH_PIN);
|
||||||
if (!(readl(DANUBE_LED_CON0) & LED_CON0_SWU))
|
LED_SH_OPENDRAIN_SETUP(LED_SH_PORT, LED_SH_PIN);
|
||||||
{
|
|
||||||
*DANUBE_LED_CON0 |= 1 << 31;
|
|
||||||
up(&led_sem);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
up(&led_sem);
|
|
||||||
for ( j = 0; j < 1000 * 16; j++ );
|
|
||||||
}
|
|
||||||
|
|
||||||
return -EBUSY;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline unsigned int
|
static void
|
||||||
set_update_source (unsigned int reg, unsigned long led, unsigned long source)
|
danube_led_enable (void)
|
||||||
{
|
{
|
||||||
return (reg & ~((led & 0x03) << 24)) | ((source & 0x03) << 24);
|
int err = 1000000;
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
writel(readl(DANUBE_PMU_PWDCR) & ~DANUBE_PMU_PWDCR_LED, DANUBE_PMU_PWDCR);
|
||||||
set_blink_in_batch (unsigned int reg, unsigned long mask, unsigned long blink)
|
while (--err && (readl(DANUBE_PMU_PWDSR) & DANUBE_PMU_PWDCR_LED)) {}
|
||||||
{
|
|
||||||
return (reg & (~(mask & 0x00FFFFFF) & 0x87FFFFFF)) | (blink & 0x00FFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
if (!err)
|
||||||
set_data_clock_edge (unsigned int reg, unsigned long f_on_rising_edge)
|
panic("Activating LED in PMU failed!");
|
||||||
{
|
|
||||||
return f_on_rising_edge ? (reg & ~(1 << 26)) : (reg | (1 << 26));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
|
||||||
set_update_clock (unsigned int reg, unsigned long clock, unsigned long fpid)
|
|
||||||
{
|
|
||||||
switch ( clock )
|
|
||||||
{
|
|
||||||
case 0:
|
|
||||||
reg &= ~0xC0000000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 1:
|
|
||||||
reg = (reg & ~0xC0000000) | 0x40000000;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 2:
|
|
||||||
reg = (reg & ~0xCF800000) | 0x80000000 | ((fpid & 0x1F) << 23);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return reg;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
|
||||||
set_store_mode (unsigned int reg, unsigned long mode)
|
|
||||||
{
|
|
||||||
return mode ? (reg | (1 << 28)) : (reg & ~(1 << 28));
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
|
||||||
unsigned int set_shift_clock (unsigned int reg, unsigned long fpis)
|
|
||||||
{
|
|
||||||
return SET_BITS(reg, 21, 20, fpis);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
|
||||||
unsigned int set_data_offset (unsigned int reg, unsigned long offset)
|
|
||||||
{
|
|
||||||
return SET_BITS(reg, 19, 18, offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline
|
|
||||||
unsigned int set_number_of_enabled_led (unsigned int reg, unsigned long number)
|
|
||||||
{
|
|
||||||
unsigned int bit_mask;
|
|
||||||
|
|
||||||
bit_mask = number > 16 ? 0x07 : (number > 8 ? 0x03 : (number ? 0x01 : 0x00));
|
|
||||||
return (reg & ~0x07) | bit_mask;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
|
||||||
set_data_in_batch (unsigned int reg, unsigned long mask, unsigned long data)
|
|
||||||
{
|
|
||||||
return (reg & ~(mask & 0x00FFFFFF)) | (data & 0x00FFFFFF);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline unsigned int
|
|
||||||
set_access_right (unsigned int reg, unsigned long mask, unsigned long ar)
|
|
||||||
{
|
|
||||||
return (reg & ~(mask & 0x00FFFFFF)) | (~ar & mask);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
enable_led (void)
|
danube_led_disable (void)
|
||||||
{
|
{
|
||||||
/* Activate LED module in PMU. */
|
writel(readl(DANUBE_PMU_PWDCR) | DANUBE_PMU_PWDCR_LED, DANUBE_PMU_PWDCR);
|
||||||
int i = 1000000;
|
|
||||||
|
|
||||||
writel(readl(DANUBE_PMU_PWDCR) & ~DANUBE_PMU_PWDCR_LED, DANUBE_PMU_PWDCR);
|
|
||||||
while (--i && (readl(DANUBE_PMU_PWDSR) & DANUBE_PMU_PWDCR_LED)) {}
|
|
||||||
|
|
||||||
if (!i)
|
|
||||||
panic("Activating LED in PMU failed!");
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
disable_led (void)
|
|
||||||
{
|
|
||||||
writel(readl(DANUBE_PMU_PWDCR) | DANUBE_PMU_PWDCR_LED, DANUBE_PMU_PWDCR);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
release_gpio_port (unsigned long adsl)
|
|
||||||
{
|
|
||||||
if ( adsl )
|
|
||||||
{
|
|
||||||
danube_port_free_pin(LED_ADSL0_PORT, LED_ADSL0_PIN);
|
|
||||||
danube_port_free_pin(LED_ADSL1_PORT, LED_ADSL1_PIN);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
danube_port_free_pin(LED_ST_PORT, LED_ST_PIN);
|
|
||||||
danube_port_free_pin(LED_D_PORT, LED_D_PIN);
|
|
||||||
danube_port_free_pin(LED_SH_PORT, LED_SH_PIN);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
setup_gpio_port (unsigned long adsl)
|
|
||||||
{
|
|
||||||
int ret = 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Reserve all pins before config them.
|
|
||||||
*/
|
|
||||||
if ( adsl )
|
|
||||||
{
|
|
||||||
ret |= danube_port_reserve_pin(LED_ADSL0_PORT, LED_ADSL0_PIN);
|
|
||||||
ret |= danube_port_reserve_pin(LED_ADSL1_PORT, LED_ADSL1_PIN);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ret |= danube_port_reserve_pin(LED_ST_PORT, LED_ST_PIN);
|
|
||||||
ret |= danube_port_reserve_pin(LED_D_PORT, LED_D_PIN);
|
|
||||||
ret |= danube_port_reserve_pin(LED_SH_PORT, LED_SH_PIN);
|
|
||||||
}
|
|
||||||
if ( ret )
|
|
||||||
{
|
|
||||||
release_gpio_port(adsl);
|
|
||||||
return ret; // Should be -EBUSY
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( adsl )
|
|
||||||
{
|
|
||||||
LED_ADSL0_ALTSEL0_SETUP(LED_ADSL0_PORT, LED_ADSL0_PIN);
|
|
||||||
LED_ADSL0_ALTSEL1_SETUP(LED_ADSL0_PORT, LED_ADSL0_PIN);
|
|
||||||
LED_ADSL0_DIR_SETUP(LED_ADSL0_PORT, LED_ADSL0_PIN);
|
|
||||||
LED_ADSL0_OPENDRAIN_SETUP(LED_ADSL0_PORT, LED_ADSL0_PIN);
|
|
||||||
|
|
||||||
LED_ADSL1_ALTSEL0_SETUP(LED_ADSL1_PORT, LED_ADSL1_PIN);
|
|
||||||
LED_ADSL1_ALTSEL1_SETUP(LED_ADSL1_PORT, LED_ADSL1_PIN);
|
|
||||||
LED_ADSL1_DIR_SETUP(LED_ADSL1_PORT, LED_ADSL1_PIN);
|
|
||||||
LED_ADSL1_OPENDRAIN_SETUP(LED_ADSL1_PORT, LED_ADSL1_PIN);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Set LED_ST
|
|
||||||
* I don't check the return value, because I'm sure the value is valid
|
|
||||||
* and the pins are reserved already.
|
|
||||||
*/
|
|
||||||
LED_ST_ALTSEL0_SETUP(LED_ST_PORT, LED_ST_PIN);
|
|
||||||
LED_ST_ALTSEL1_SETUP(LED_ST_PORT, LED_ST_PIN);
|
|
||||||
LED_ST_DIR_SETUP(LED_ST_PORT, LED_ST_PIN);
|
|
||||||
LED_ST_OPENDRAIN_SETUP(LED_ST_PORT, LED_ST_PIN);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set LED_D
|
|
||||||
*/
|
|
||||||
LED_D_ALTSEL0_SETUP(LED_D_PORT, LED_D_PIN);
|
|
||||||
LED_D_ALTSEL1_SETUP(LED_D_PORT, LED_D_PIN);
|
|
||||||
LED_D_DIR_SETUP(LED_D_PORT, LED_D_PIN);
|
|
||||||
LED_D_OPENDRAIN_SETUP(LED_D_PORT, LED_D_PIN);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Set LED_SH
|
|
||||||
*/
|
|
||||||
LED_SH_ALTSEL0_SETUP(LED_SH_PORT, LED_SH_PIN);
|
|
||||||
LED_SH_ALTSEL1_SETUP(LED_SH_PORT, LED_SH_PIN);
|
|
||||||
LED_SH_DIR_SETUP(LED_SH_PORT, LED_SH_PIN);
|
|
||||||
LED_SH_OPENDRAIN_SETUP(LED_SH_PORT, LED_SH_PIN);
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
setup_gpt (int timer, unsigned long freq)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
timer = TIMER(timer, 1);
|
|
||||||
|
|
||||||
ret = request_timer(timer,
|
|
||||||
TIMER_FLAG_SYNC
|
|
||||||
| TIMER_FLAG_16BIT
|
|
||||||
| TIMER_FLAG_INT_SRC
|
|
||||||
| TIMER_FLAG_CYCLIC | TIMER_FLAG_COUNTER | TIMER_FLAG_DOWN
|
|
||||||
| TIMER_FLAG_ANY_EDGE
|
|
||||||
| TIMER_FLAG_NO_HANDLE,
|
|
||||||
8000000 / freq,
|
|
||||||
0,
|
|
||||||
0);
|
|
||||||
|
|
||||||
if ( !ret )
|
|
||||||
{
|
|
||||||
ret = start_timer(timer, 0);
|
|
||||||
if ( ret )
|
|
||||||
free_timer(timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
release_gpt (int timer)
|
|
||||||
{
|
|
||||||
timer = TIMER(timer, 1);
|
|
||||||
stop_timer(timer);
|
|
||||||
free_timer(timer);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
turn_on_led (unsigned long adsl)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
ret = setup_gpio_port(adsl);
|
|
||||||
if ( ret )
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
enable_led();
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void
|
|
||||||
turn_off_led (unsigned long adsl)
|
|
||||||
{
|
|
||||||
release_gpio_port(adsl);
|
|
||||||
disable_led();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int
|
|
||||||
danube_led_set_blink (unsigned int led, unsigned int blink)
|
|
||||||
{
|
|
||||||
unsigned int bit_mask;
|
|
||||||
|
|
||||||
if ( led > 23 )
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
bit_mask = 1 << led;
|
|
||||||
down(&led_sem);
|
|
||||||
if ( blink )
|
|
||||||
*DANUBE_LED_CON0 |= bit_mask;
|
|
||||||
else
|
|
||||||
*DANUBE_LED_CON0 &= ~bit_mask;
|
|
||||||
up(&led_sem);
|
|
||||||
|
|
||||||
return (led == 0 && (readl(DANUBE_LED_CON0) & LED_CON0_AD0)) || (led == 1 && (readl(DANUBE_LED_CON0) & LED_CON0_AD1)) ? -EINVAL : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
danube_led_set_data (unsigned int led, unsigned int data)
|
|
||||||
{
|
|
||||||
unsigned long f_update;
|
|
||||||
unsigned int bit_mask;
|
|
||||||
|
|
||||||
if ( led > 23 )
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
bit_mask = 1 << led;
|
|
||||||
down(&led_sem);
|
|
||||||
if ( data )
|
|
||||||
*DANUBE_LED_CPU0 |= bit_mask;
|
|
||||||
else
|
|
||||||
*DANUBE_LED_CPU0 &= ~bit_mask;
|
|
||||||
f_update = !(*DANUBE_LED_AR & bit_mask);
|
|
||||||
up(&led_sem);
|
|
||||||
|
|
||||||
return f_update ? update_led() : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
danube_led_config (struct led_config_param* param)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
unsigned int reg_con0, reg_con1, reg_cpu0, reg_ar;
|
|
||||||
unsigned int clean_reg_con0, clean_reg_con1, clean_reg_cpu0, clean_reg_ar;
|
|
||||||
unsigned int f_setup_gpt2;
|
|
||||||
unsigned int f_software_update;
|
|
||||||
unsigned int new_led_on, new_adsl_on;
|
|
||||||
|
|
||||||
if ( !param )
|
|
||||||
return -EINVAL;
|
|
||||||
|
|
||||||
down(&led_sem);
|
|
||||||
|
|
||||||
reg_con0 = *DANUBE_LED_CON0;
|
|
||||||
reg_con1 = *DANUBE_LED_CON1;
|
|
||||||
reg_cpu0 = *DANUBE_LED_CPU0;
|
|
||||||
reg_ar = *DANUBE_LED_AR;
|
|
||||||
|
|
||||||
clean_reg_con0 = 1;
|
|
||||||
clean_reg_con1 = 1;
|
|
||||||
clean_reg_cpu0 = 1;
|
|
||||||
clean_reg_ar = 1;
|
|
||||||
|
|
||||||
f_setup_gpt2 = 0;
|
|
||||||
|
|
||||||
f_software_update = (readl(DANUBE_LED_CON0) & LED_CON0_SWU) ? 0 : 1;
|
|
||||||
|
|
||||||
new_led_on = f_led_on;
|
|
||||||
new_adsl_on = adsl_on;
|
|
||||||
|
|
||||||
/* ADSL or LED */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_UPDATE_SOURCE) )
|
|
||||||
{
|
|
||||||
if ( param->led > 0x03 || param->source > 0x03 )
|
|
||||||
goto INVALID_PARAM;
|
|
||||||
clean_reg_con0 = 0;
|
|
||||||
reg_con0 = set_update_source(reg_con0, param->led, param->source);
|
|
||||||
#if 0 // ADSL0,1 is source for bit 0, 1 in shift register
|
|
||||||
new_adsl_on = param->source;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Blink */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_BLINK) )
|
|
||||||
{
|
|
||||||
if ( (param->blink_mask & 0xFF000000) || (param->blink & 0xFF000000) )
|
|
||||||
goto INVALID_PARAM;
|
|
||||||
clean_reg_con0 = 0;
|
|
||||||
reg_con0 = set_blink_in_batch(reg_con0, param->blink_mask, param->blink);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Edge */
|
|
||||||
if ( (param->operation_mask & CONFIG_DATA_CLOCK_EDGE) )
|
|
||||||
{
|
|
||||||
clean_reg_con0 = 0;
|
|
||||||
reg_con0 = set_data_clock_edge(reg_con0, param->f_data_clock_on_rising);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Update Clock */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_UPDATE_CLOCK) )
|
|
||||||
{
|
|
||||||
if ( param->update_clock > 0x02 || (param->update_clock == 0x02 && param->fpid > 0x3) )
|
|
||||||
goto INVALID_PARAM;
|
|
||||||
clean_reg_con1 = 0;
|
|
||||||
f_software_update = param->update_clock == 0 ? 1 : 0;
|
|
||||||
if ( param->update_clock == 0x01 )
|
|
||||||
f_setup_gpt2 = 1;
|
|
||||||
reg_con1 = set_update_clock(reg_con1, param->update_clock, param->fpid);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Store Mode */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_STORE_MODE) )
|
|
||||||
{
|
|
||||||
clean_reg_con1 = 0;
|
|
||||||
reg_con1 = set_store_mode(reg_con1, param->store_mode);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Shift Clock */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_SHIFT_CLOCK) )
|
|
||||||
{
|
|
||||||
if ( param->fpis > 0x03 )
|
|
||||||
goto INVALID_PARAM;
|
|
||||||
clean_reg_con1 = 0;
|
|
||||||
reg_con1 = set_shift_clock(reg_con1, param->fpis);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Data Offset */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_DATA_OFFSET) )
|
|
||||||
{
|
|
||||||
if ( param->data_offset > 0x03 )
|
|
||||||
goto INVALID_PARAM;
|
|
||||||
clean_reg_con1 = 0;
|
|
||||||
reg_con1 = set_data_offset(reg_con1, param->data_offset);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Number of LED */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_NUMBER_OF_LED) )
|
|
||||||
{
|
|
||||||
if ( param->number_of_enabled_led > 0x24 )
|
|
||||||
goto INVALID_PARAM;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* If there is at lease one LED enabled, the GPIO pin must be setup.
|
|
||||||
*/
|
|
||||||
new_led_on = param->number_of_enabled_led ? 1 : 0;
|
|
||||||
|
|
||||||
clean_reg_con1 = 0;
|
|
||||||
reg_con1 = set_number_of_enabled_led(reg_con1, param->number_of_enabled_led);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* LED Data */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_DATA) )
|
|
||||||
{
|
|
||||||
if ( (param->data_mask & 0xFF000000) || (param->data & 0xFF000000) )
|
|
||||||
goto INVALID_PARAM;
|
|
||||||
clean_reg_cpu0 = 0;
|
|
||||||
reg_cpu0 = set_data_in_batch(reg_cpu0, param->data_mask, param->data);
|
|
||||||
if ( f_software_update )
|
|
||||||
{
|
|
||||||
clean_reg_con0 = 0;
|
|
||||||
reg_con0 |= 0x80000000;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Access Right */
|
|
||||||
if ( (param->operation_mask & CONFIG_OPERATION_MIPS0_ACCESS) )
|
|
||||||
{
|
|
||||||
if ( (param->mips0_access_mask & 0xFF000000) || (param->mips0_access & 0xFF000000) )
|
|
||||||
goto INVALID_PARAM;
|
|
||||||
clean_reg_ar = 0;
|
|
||||||
reg_ar = set_access_right(reg_ar, param->mips0_access_mask, param->mips0_access);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Setup GPT */
|
|
||||||
if ( f_setup_gpt2 && !new_adsl_on ) // If ADSL led is on, GPT is disabled.
|
|
||||||
{
|
|
||||||
ret = 0;
|
|
||||||
|
|
||||||
if ( gpt_on )
|
|
||||||
{
|
|
||||||
if ( gpt_freq != param->fpid )
|
|
||||||
{
|
|
||||||
release_gpt(2);
|
|
||||||
gpt_on = 0;
|
|
||||||
ret = setup_gpt(2, param->fpid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ret = setup_gpt(2, param->fpid);
|
|
||||||
|
|
||||||
if ( ret )
|
|
||||||
{
|
|
||||||
#if 1
|
|
||||||
printk("Setup GPT error!\n");
|
|
||||||
#endif
|
|
||||||
goto SETUP_GPT_ERROR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#if 0
|
|
||||||
printk("Setup GPT successfully!\n");
|
|
||||||
#endif
|
|
||||||
gpt_on = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
if ( gpt_on )
|
|
||||||
{
|
|
||||||
release_gpt(2);
|
|
||||||
gpt_on = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Turn on LED */
|
|
||||||
if ( new_adsl_on )
|
|
||||||
new_led_on = 1;
|
|
||||||
if ( !new_led_on || adsl_on != new_adsl_on )
|
|
||||||
{
|
|
||||||
turn_off_led(adsl_on);
|
|
||||||
f_led_on = 0;
|
|
||||||
adsl_on = 0;
|
|
||||||
}
|
|
||||||
if ( !f_led_on && new_led_on )
|
|
||||||
{
|
|
||||||
ret = turn_on_led(new_adsl_on);
|
|
||||||
if ( ret )
|
|
||||||
{
|
|
||||||
printk("Setup GPIO error!\n");
|
|
||||||
goto SETUP_GPIO_ERROR;
|
|
||||||
}
|
|
||||||
adsl_on = new_adsl_on;
|
|
||||||
f_led_on = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Write Register */
|
|
||||||
if ( !f_led_on )
|
|
||||||
enable_led();
|
|
||||||
if ( !clean_reg_ar )
|
|
||||||
*DANUBE_LED_AR = reg_ar;
|
|
||||||
if ( !clean_reg_cpu0 )
|
|
||||||
*DANUBE_LED_CPU0 = reg_cpu0;
|
|
||||||
if ( !clean_reg_con1 )
|
|
||||||
*DANUBE_LED_CON1 = reg_con1;
|
|
||||||
if ( !clean_reg_con0 )
|
|
||||||
*DANUBE_LED_CON0 = reg_con0;
|
|
||||||
if ( !f_led_on )
|
|
||||||
disable_led();
|
|
||||||
|
|
||||||
up(&led_sem);
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
SETUP_GPIO_ERROR:
|
|
||||||
release_gpt(2);
|
|
||||||
gpt_on = 0;
|
|
||||||
SETUP_GPT_ERROR:
|
|
||||||
up(&led_sem);
|
|
||||||
return ret;
|
|
||||||
|
|
||||||
INVALID_PARAM:
|
|
||||||
up(&led_sem);
|
|
||||||
return -EINVAL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
led_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
led_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
|
||||||
{
|
{
|
||||||
int ret = -EINVAL;
|
int ret = -EINVAL;
|
||||||
struct led_config_param param;
|
|
||||||
|
|
||||||
switch ( cmd )
|
switch ( cmd )
|
||||||
{
|
{
|
||||||
case LED_CONFIG:
|
case LED_CONFIG:
|
||||||
copy_from_user(¶m, (char*)arg, sizeof(param));
|
break;
|
||||||
ret = danube_led_config(¶m);
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
led_open (struct inode *inode, struct file *file)
|
led_open (struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
led_release (struct inode *inode, struct file *file)
|
led_release (struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct file_operations led_fops = {
|
static struct file_operations danube_led_fops = {
|
||||||
owner: THIS_MODULE,
|
.owner = THIS_MODULE,
|
||||||
ioctl: led_ioctl,
|
.ioctl = led_ioctl,
|
||||||
open: led_open,
|
.open = led_open,
|
||||||
release: led_release
|
.release = led_release
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct miscdevice led_miscdev = {
|
|
||||||
151,
|
/*
|
||||||
"led",
|
Map for LED on reference board
|
||||||
&led_fops,
|
WLAN_READ LED11 OUT1 15
|
||||||
NULL,
|
WARNING LED12 OUT2 14
|
||||||
NULL,
|
FXS1_LINK LED13 OUT3 13
|
||||||
NULL
|
FXS2_LINK LED14 OUT4 12
|
||||||
};
|
FXO_ACT LED15 OUT5 11
|
||||||
|
USB_LINK LED16 OUT6 10
|
||||||
|
ADSL2_LINK LED19 OUT7 9
|
||||||
|
BT_LINK LED17 OUT8 8
|
||||||
|
SD_LINK LED20 OUT9 7
|
||||||
|
ADSL2_TRAFFIC LED31 OUT16 0
|
||||||
|
Map for hardware relay on reference board
|
||||||
|
USB Power On OUT11 5
|
||||||
|
RELAY OUT12 4
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
int __init
|
int __init
|
||||||
danube_led_init (void)
|
danube_led_init (void)
|
||||||
{
|
{
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct led_config_param param = {0};
|
|
||||||
|
|
||||||
enable_led();
|
danube_led_setup_gpio();
|
||||||
|
|
||||||
writel(0, DANUBE_LED_AR);
|
writel(0, DANUBE_LED_AR);
|
||||||
writel(0, DANUBE_LED_CPU0);
|
writel(0xff00, DANUBE_LED_CPU0);
|
||||||
writel(0, DANUBE_LED_CPU1);
|
writel(0, DANUBE_LED_CPU1);
|
||||||
writel(0, DANUBE_LED_CON1);
|
writel(0x8000ffff, DANUBE_LED_CON0);
|
||||||
writel((0x80000000 | (DATA_CLOCKING_EDGE << 26)), DANUBE_LED_CON0);
|
|
||||||
|
|
||||||
disable_led();
|
/* setup the clock edge that the shift register is triggered on */
|
||||||
|
writel(readl(DANUBE_LED_CON0) & ~DANUBE_LED_EDGE_MASK, DANUBE_LED_CON0);
|
||||||
|
writel(readl(DANUBE_LED_CON0) | DANUBE_LED_CLK_EDGE, DANUBE_LED_CON0);
|
||||||
|
|
||||||
sema_init(&led_sem, 0);
|
/* per default leds 15-0 are set */
|
||||||
|
writel(DANUBE_LED_GROUP1 | DANUBE_LED_GROUP0, DANUBE_LED_CON1);
|
||||||
|
|
||||||
ret = misc_register(&led_miscdev);
|
/* leds are update periodically by the FPID */
|
||||||
if (ret == -EBUSY)
|
writel(readl(DANUBE_LED_CON1) & ~DANUBE_LED_UPD_MASK, DANUBE_LED_CON1);
|
||||||
{
|
writel(readl(DANUBE_LED_CON1) | DANUBE_LED_UPD_SRC_FPI, DANUBE_LED_CON1);
|
||||||
led_miscdev.minor = MISC_DYNAMIC_MINOR;
|
|
||||||
ret = misc_register(&led_miscdev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ret)
|
/* set led update speed */
|
||||||
{
|
writel(readl(DANUBE_LED_CON1) & ~DANUBE_LED_MASK, DANUBE_LED_CON1);
|
||||||
printk(KERN_ERR "led: can't misc_register\n");
|
writel(readl(DANUBE_LED_CON1) | DANUBE_LED_8HZ, DANUBE_LED_CON1);
|
||||||
goto out;
|
|
||||||
} else {
|
/* adsl 0 and 1 leds are updated by the arc */
|
||||||
printk(KERN_INFO "led: misc_register on minor = %d\n", led_miscdev.minor);
|
writel(readl(DANUBE_LED_CON0) | DANUBE_LED_ADSL_SRC, DANUBE_LED_CON0);
|
||||||
|
|
||||||
|
/* per default, the leds are turned on */
|
||||||
|
danube_led_enable();
|
||||||
|
|
||||||
|
danube_led_major = register_chrdev(0, "danube_led", &danube_led_fops);
|
||||||
|
|
||||||
|
if (!danube_led_major)
|
||||||
|
{
|
||||||
|
printk("danube_led: Error! Could not register device. %d\n", danube_led_major);
|
||||||
|
ret = -EINVAL;
|
||||||
|
|
||||||
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
up(&led_sem);
|
printk(KERN_INFO "danube_led : device registered on major %d\n", danube_led_major);
|
||||||
|
|
||||||
/* Add to enable hardware relay */
|
|
||||||
/* Map for LED on reference board
|
|
||||||
WLAN_READ LED11 OUT1 15
|
|
||||||
WARNING LED12 OUT2 14
|
|
||||||
FXS1_LINK LED13 OUT3 13
|
|
||||||
FXS2_LINK LED14 OUT4 12
|
|
||||||
FXO_ACT LED15 OUT5 11
|
|
||||||
USB_LINK LED16 OUT6 10
|
|
||||||
ADSL2_LINK LED19 OUT7 9
|
|
||||||
BT_LINK LED17 OUT8 8
|
|
||||||
SD_LINK LED20 OUT9 7
|
|
||||||
ADSL2_TRAFFIC LED31 OUT16 0
|
|
||||||
Map for hardware relay on reference board
|
|
||||||
USB Power On OUT11 5
|
|
||||||
RELAY OUT12 4
|
|
||||||
*/
|
|
||||||
param.operation_mask = CONFIG_OPERATION_NUMBER_OF_LED;
|
|
||||||
param.number_of_enabled_led = 16;
|
|
||||||
danube_led_config(¶m);
|
|
||||||
param.operation_mask = CONFIG_OPERATION_DATA;
|
|
||||||
param.data_mask = 1 << 4;
|
|
||||||
param.data = 1 << 4;
|
|
||||||
danube_led_config(¶m);
|
|
||||||
|
|
||||||
// by default, update by FSC clock (FPID)
|
|
||||||
param.operation_mask = CONFIG_OPERATION_UPDATE_CLOCK;
|
|
||||||
param.update_clock = 2; // FPID
|
|
||||||
param.fpid = 3; // 10Hz
|
|
||||||
danube_led_config(¶m);
|
|
||||||
|
|
||||||
// source of LED 0, 1 is ADSL
|
|
||||||
param.operation_mask = CONFIG_OPERATION_UPDATE_SOURCE;
|
|
||||||
param.led = 3; // LED 0, 1
|
|
||||||
param.source = 3; // ADSL
|
|
||||||
danube_led_config(¶m);
|
|
||||||
|
|
||||||
// turn on USB
|
|
||||||
param.operation_mask = CONFIG_OPERATION_DATA;
|
|
||||||
param.data_mask = 1 << 5;
|
|
||||||
param.data = 1 << 5;
|
|
||||||
danube_led_config(¶m);
|
|
||||||
|
|
||||||
out:
|
out:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void __exit
|
void __exit
|
||||||
danube_led_exit (void)
|
danube_led_exit (void)
|
||||||
{
|
{
|
||||||
int ret;
|
unregister_chrdev(danube_led_major, "danube_led");
|
||||||
|
|
||||||
ret = misc_deregister(&led_miscdev);
|
|
||||||
if ( ret )
|
|
||||||
printk(KERN_ERR "led: can't misc_deregister, get error number %d\n", -ret);
|
|
||||||
else
|
|
||||||
printk(KERN_INFO "led: misc_deregister successfully\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
EXPORT_SYMBOL(danube_led_set_blink);
|
|
||||||
EXPORT_SYMBOL(danube_led_set_data);
|
|
||||||
EXPORT_SYMBOL(danube_led_config);
|
|
||||||
|
|
||||||
module_init(danube_led_init);
|
module_init(danube_led_init);
|
||||||
module_exit(danube_led_exit);
|
module_exit(danube_led_exit);
|
||||||
|
|
||||||
|
|
|
@ -309,6 +309,25 @@
|
||||||
#define LED_CON0_AD1 (1 << 25)
|
#define LED_CON0_AD1 (1 << 25)
|
||||||
#define LED_CON0_AD0 (1 << 24)
|
#define LED_CON0_AD0 (1 << 24)
|
||||||
|
|
||||||
|
#define DANUBE_LED_2HZ (0)
|
||||||
|
#define DANUBE_LED_4HZ (1 << 23)
|
||||||
|
#define DANUBE_LED_8HZ (2 << 23)
|
||||||
|
#define DANUBE_LED_10HZ (3 << 23)
|
||||||
|
#define DANUBE_LED_MASK (0xf << 23)
|
||||||
|
|
||||||
|
#define DANUBE_LED_UPD_SRC_FPI (1 << 31)
|
||||||
|
#define DANUBE_LED_UPD_MASK (3 << 30)
|
||||||
|
#define DANUBE_LED_ADSL_SRC (3 << 24)
|
||||||
|
|
||||||
|
#define DANUBE_LED_GROUP0 (1 << 0)
|
||||||
|
#define DANUBE_LED_GROUP1 (1 << 1)
|
||||||
|
#define DANUBE_LED_GROUP2 (1 << 2)
|
||||||
|
|
||||||
|
#define DANUBE_LED_RISING 0
|
||||||
|
#define DANUBE_LED_FALLING (1 << 26)
|
||||||
|
#define DANUBE_LED_EDGE_MASK (1 << 26)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*------------ GPIO */
|
/*------------ GPIO */
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue