From: John Crispin Date: Sat, 22 Dec 2007 14:00:25 +0000 (+0000) Subject: more danube 2 ifxmips transitions X-Git-Url: http://git.lede-project.org./?a=commitdiff_plain;h=d6211ec9e6a5c600c5246a88288fc1ccf5cd06da;p=openwrt%2Fstaging%2Frobimarko.git more danube 2 ifxmips transitions SVN-Revision: 9826 --- diff --git a/target/linux/ifxmips/files/drivers/char/danube_eeprom.c b/target/linux/ifxmips/files/drivers/char/danube_eeprom.c deleted file mode 100644 index ea1303cd66..0000000000 --- a/target/linux/ifxmips/files/drivers/char/danube_eeprom.c +++ /dev/null @@ -1,541 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - * - * This driver was originally based on the INCA-IP driver, but due to - * fundamental conceptual drawbacks there has been changed a lot. - * - * Based on INCA-IP driver Copyright (c) 2003 Gary Jennejohn - * Based on the VxWorks drivers Copyright (c) 2002, Infineon Technologies. - * - * Copyright (C) 2006 infineon - * Copyright (C) 2007 John Crispin - * - */ - -#define IFAP_EEPROM_DRV_VERSION "0.0.1" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -/* allow the user to set the major device number */ -static int ifxmips_eeprom_maj = 0; - -extern int ifx_ssc_init (void); -extern int ifx_ssc_open (struct inode *inode, struct file *filp); -extern int ifx_ssc_close (struct inode *inode, struct file *filp); -extern void ifx_ssc_cleanup_module (void); -extern int ifx_ssc_ioctl (struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long data); -extern ssize_t ifx_ssc_kwrite (int port, const char *kbuf, size_t len); -extern ssize_t ifx_ssc_kread (int port, char *kbuf, size_t len); - -extern int ifx_ssc_cs_low (unsigned int pin); -extern int ifx_ssc_cs_high (unsigned int pin); -extern int ifx_ssc_txrx (char *tx_buf, unsigned int tx_len, char *rx_buf, unsigned int rx_len); -extern int ifx_ssc_tx (char *tx_buf, unsigned int tx_len); -extern int ifx_ssc_rx (char *rx_buf, unsigned int rx_len); - -#define EEPROM_CS IFX_SSC_WHBGPOSTAT_OUT0_POS - -/* commands for EEPROM, x25160, x25140 */ -#define EEPROM_WREN ((unsigned char)0x06) -#define EEPROM_WRDI ((unsigned char)0x04) -#define EEPROM_RDSR ((unsigned char)0x05) -#define EEPROM_WRSR ((unsigned char)0x01) -#define EEPROM_READ ((unsigned char)0x03) -#define EEPROM_WRITE ((unsigned char)0x02) -#define EEPROM_PAGE_SIZE 4 -#define EEPROM_SIZE 512 - -static int -eeprom_rdsr (void) -{ - int ret = 0; - unsigned char cmd = EEPROM_RDSR; - unsigned long flag; - char status; - - local_irq_save(flag); - - if ((ret = ifx_ssc_cs_low(EEPROM_CS)) == 0) - if ((ret = ifx_ssc_txrx(&cmd, 1, &status, 1)) >= 0) - ret = status & 1; - - ifx_ssc_cs_high(EEPROM_CS); - local_irq_restore(flag); - - return ret; -} - -void -eeprom_wip_over (void) -{ - while (eeprom_rdsr()) - printk("waiting for eeprom\n"); -} - -static int -eeprom_wren (void) -{ - unsigned char cmd = EEPROM_WREN; - int ret = 0; - unsigned long flag; - - local_irq_save(flag); - if ((ret = ifx_ssc_cs_low(EEPROM_CS)) == 0) - if ((ret = ifx_ssc_tx(&cmd, 1)) >= 0) - ret = 0; - - ifx_ssc_cs_high(EEPROM_CS); - local_irq_restore(flag); - - if (!ret) - eeprom_wip_over(); - - return ret; -} - -static int -eeprom_wrsr (void) -{ - int ret = 0; - unsigned char cmd[2]; - unsigned long flag; - - cmd[0] = EEPROM_WRSR; - cmd[1] = 0; - - if ((ret = eeprom_wren())) - { - printk ("eeprom_wren fails\n"); - goto out1; - } - - local_irq_save(flag); - - if ((ret = ifx_ssc_cs_low(EEPROM_CS))) - goto out; - - if ((ret = ifx_ssc_tx(cmd, 2)) < 0) { - ifx_ssc_cs_high(EEPROM_CS); - goto out; - } - - if ((ret = ifx_ssc_cs_low(EEPROM_CS))) - goto out; - - local_irq_restore(flag); - eeprom_wip_over(); - - return ret; - -out: - local_irq_restore (flag); - eeprom_wip_over (); - -out1: - return ret; -} - -static int -eeprom_read (unsigned int addr, unsigned char *buf, unsigned int len) -{ - int ret = 0; - unsigned char write_buf[2]; - unsigned int eff = 0; - unsigned long flag; - - while (1) - { - eeprom_wip_over(); - eff = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE); - eff = (eff < len) ? eff : len; - local_irq_save(flag); - - if ((ret = ifx_ssc_cs_low(EEPROM_CS)) < 0) - goto out; - - write_buf[0] = EEPROM_READ | ((unsigned char) ((addr & 0x100) >> 5)); - write_buf[1] = (addr & 0xff); - - if ((ret = ifx_ssc_txrx (write_buf, 2, buf, eff)) != eff) - { - printk("ssc_txrx fails %d\n", ret); - ifx_ssc_cs_high (EEPROM_CS); - goto out; - } - - buf += ret; - len -= ret; - addr += ret; - - if ((ret = ifx_ssc_cs_high(EEPROM_CS))) - goto out; - - local_irq_restore(flag); - - if (len <= 0) - goto out2; - } - -out: - local_irq_restore (flag); -out2: - return ret; -} - -static int -eeprom_write (unsigned int addr, unsigned char *buf, unsigned int len) -{ - int ret = 0; - unsigned int eff = 0; - unsigned char write_buf[2]; - int i; - unsigned char rx_buf[EEPROM_PAGE_SIZE]; - - while (1) - { - eeprom_wip_over(); - - if ((ret = eeprom_wren())) - { - printk("eeprom_wren fails\n"); - goto out; - } - - write_buf[0] = EEPROM_WRITE | ((unsigned char) ((addr & 0x100) >> 5)); - write_buf[1] = (addr & 0xff); - - eff = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE); - eff = (eff < len) ? eff : len; - - printk("EEPROM Write:\n"); - for (i = 0; i < eff; i++) { - printk("%2x ", buf[i]); - if ((i % 16) == 15) - printk("\n"); - } - printk("\n"); - - if ((ret = ifx_ssc_cs_low(EEPROM_CS))) - goto out; - - if ((ret = ifx_ssc_tx (write_buf, 2)) < 0) - { - printk("ssc_tx fails %d\n", ret); - ifx_ssc_cs_high(EEPROM_CS); - goto out; - } - - if ((ret = ifx_ssc_tx (buf, eff)) != eff) - { - printk("ssc_tx fails %d\n", ret); - ifx_ssc_cs_high(EEPROM_CS); - goto out; - } - - buf += ret; - len -= ret; - addr += ret; - - if ((ret = ifx_ssc_cs_high (EEPROM_CS))) - goto out; - - printk ("<=="); - eeprom_read((addr - eff), rx_buf, eff); - for (i = 0; i < eff; i++) - { - printk ("[%x]", rx_buf[i]); - } - printk ("\n"); - - if (len <= 0) - break; - } - -out: - return ret; -} - -int -ifxmips_eeprom_open (struct inode *inode, struct file *filp) -{ - filp->f_pos = 0; - return 0; -} - -int -ifxmips_eeprom_close (struct inode *inode, struct file *filp) -{ - return 0; -} - -int -ifxmips_eeprom_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) -{ - return 0; -} - -ssize_t -ifxmips_eeprom_read (char *buf, size_t len, unsigned int addr) -{ - int ret = 0; - unsigned int data; - - printk("addr:=%d\n", addr); - printk("len:=%d\n", len); - - if ((addr + len) > EEPROM_SIZE) - { - printk("invalid len\n"); - addr = 0; - len = EEPROM_SIZE / 2; - } - - if ((ret = ifx_ssc_open((struct inode *) 0, NULL))) - { - printk("ifxmips_eeprom_open fails\n"); - goto out; - } - - data = (unsigned int)IFX_SSC_MODE_RXTX; - - if ((ret = ifx_ssc_ioctl((struct inode *) 0, NULL, IFX_SSC_RXTX_MODE_SET, (unsigned long) &data))) - { - printk("set RXTX mode fails\n"); - goto out; - } - - if ((ret = eeprom_wrsr())) - { - printk("EEPROM reset fails\n"); - goto out; - } - - if ((ret = eeprom_read(addr, buf, len))) - { - printk("eeprom read fails\n"); - goto out; - } - -out: - if (ifx_ssc_close((struct inode *) 0, NULL)) - printk("ifxmips_eeprom_close fails\n"); - - return len; -} -EXPORT_SYMBOL(ifxmips_eeprom_read); - -static ssize_t -ifxmips_eeprom_fops_read (struct file *filp, char *ubuf, size_t len, loff_t * off) -{ - int ret = 0; - unsigned char ssc_rx_buf[EEPROM_SIZE]; - long flag; - - if (*off >= EEPROM_SIZE) - return 0; - - if (*off + len > EEPROM_SIZE) - len = EEPROM_SIZE - *off; - - if (len == 0) - return 0; - - local_irq_save(flag); - - if ((ret = ifxmips_eeprom_read(ssc_rx_buf, len, *off)) < 0) - { - printk("read fails, err=%x\n", ret); - local_irq_restore(flag); - return ret; - } - - if (copy_to_user((void*)ubuf, ssc_rx_buf, ret) != 0) - { - local_irq_restore(flag); - ret = -EFAULT; - } - - local_irq_restore(flag); - *off += len; - - return len; -} - -ssize_t -ifxmips_eeprom_write (char *buf, size_t len, unsigned int addr) -{ - int ret = 0; - unsigned int data; - - if ((ret = ifx_ssc_open ((struct inode *) 0, NULL))) - { - printk ("ifxmips_eeprom_open fails\n"); - goto out; - } - - data = (unsigned int) IFX_SSC_MODE_RXTX; - - if ((ret = ifx_ssc_ioctl ((struct inode *) 0, NULL, IFX_SSC_RXTX_MODE_SET, (unsigned long) &data))) - { - printk ("set RXTX mode fails\n"); - goto out; - } - - if ((ret = eeprom_wrsr ())) { - printk ("EEPROM reset fails\n"); - goto out; - } - - if ((ret = eeprom_write (addr, buf, len))) { - printk ("eeprom write fails\n"); - goto out; - } - -out: - if (ifx_ssc_close ((struct inode *) 0, NULL)) - printk ("ifxmips_eeprom_close fails\n"); - - return ret; -} -EXPORT_SYMBOL(ifxmips_eeprom_write); - -static ssize_t -ifxmips_eeprom_fops_write (struct file *filp, const char *ubuf, size_t len, loff_t * off) -{ - int ret = 0; - unsigned char ssc_tx_buf[EEPROM_SIZE]; - - if (*off >= EEPROM_SIZE) - return 0; - - if (len + *off > EEPROM_SIZE) - len = EEPROM_SIZE - *off; - - if ((ret = copy_from_user (ssc_tx_buf, ubuf, len))) - return EFAULT; - - ret = ifxmips_eeprom_write (ssc_tx_buf, len, *off); - - if (ret > 0) - *off = ret; - - return ret; -} - -loff_t -ifxmips_eeprom_llseek (struct file * filp, loff_t off, int whence) -{ - loff_t newpos; - switch (whence) { - case SEEK_SET: - newpos = off; - break; - - case SEEK_CUR: - newpos = filp->f_pos + off; - break; - - default: - return -EINVAL; - } - - if (newpos < 0) - return -EINVAL; - - filp->f_pos = newpos; - - return newpos; -} - -static struct file_operations ifxmips_eeprom_fops = { - owner:THIS_MODULE, - llseek:ifxmips_eeprom_llseek, - read:ifxmips_eeprom_fops_read, - write:ifxmips_eeprom_fops_write, - ioctl:ifxmips_eeprom_ioctl, - open:ifxmips_eeprom_open, - release:ifxmips_eeprom_close, -}; - -int __init -ifxmips_eeprom_init (void) -{ - int ret = 0; - - ifxmips_eeprom_maj = register_chrdev(0, "eeprom", &ifxmips_eeprom_fops); - - if (ifxmips_eeprom_maj < 0) - { - printk("failed to register eeprom device\n"); - ret = -EINVAL; - - goto out; - } - - printk("ifxmips_eeprom : /dev/eeprom mayor %d\n", ifxmips_eeprom_maj); - -out: - return ret; -} - -void __exit -ifxmips_eeprom_cleanup_module (void) -{ - /*if (unregister_chrdev (ifxmips_eeprom_maj, "eeprom")) { - printk ("Unable to unregister major %d for the EEPROM\n", - maj); - }*/ -} - -module_exit (ifxmips_eeprom_cleanup_module); -module_init (ifxmips_eeprom_init); - -MODULE_LICENSE ("GPL"); -MODULE_AUTHOR ("Peng Liu"); -MODULE_DESCRIPTION ("IFAP EEPROM driver"); -MODULE_SUPPORTED_DEVICE ("ifxmips_eeprom"); - - diff --git a/target/linux/ifxmips/files/drivers/char/danube_gpio.c b/target/linux/ifxmips/files/drivers/char/danube_gpio.c deleted file mode 100644 index 6ac9ec6b17..0000000000 --- a/target/linux/ifxmips/files/drivers/char/danube_gpio.c +++ /dev/null @@ -1,442 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) 2005 infineon - * Copyright (C) 2007 John Crispin - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MAX_PORTS 2 -#define PINS_PER_PORT 16 - -static unsigned int ifxmips_gpio_major = 0; - -/* TODO do we need this ? */ -static struct semaphore port_sem; - -/* TODO do we really need this ? return in a define is forbidden by coding style */ -#define IFXMIPS_GPIO_SANITY {if (port > MAX_PORTS || pin > PINS_PER_PORT) return -EINVAL; } - -int -ifxmips_port_reserve_pin (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - printk("%s : call to obseleted function\n", __func__); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_reserve_pin); - -int -ifxmips_port_free_pin (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - printk("%s : call to obseleted function\n", __func__); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_free_pin); - -int -ifxmips_port_set_open_drain (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_OD + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_OD); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_open_drain); - -int -ifxmips_port_clear_open_drain (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_OD + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_OD); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_clear_open_drain); - -int -ifxmips_port_set_pudsel (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_PUDSEL + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_PUDSEL); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_pudsel); - -int -ifxmips_port_clear_pudsel (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_PUDSEL + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_PUDSEL); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_clear_pudsel); - -int -ifxmips_port_set_puden (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_PUDEN + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_PUDEN); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_puden); - -int -ifxmips_port_clear_puden (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_PUDEN + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_PUDEN); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_clear_puden); - -int -ifxmips_port_set_stoff (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_STOFF + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_STOFF); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_stoff); - -int -ifxmips_port_clear_stoff (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_STOFF + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_STOFF); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_clear_stoff); - -int -ifxmips_port_set_dir_out (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_DIR + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_DIR); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_dir_out); - -int -ifxmips_port_set_dir_in (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_DIR + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_DIR); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_dir_in); - -int -ifxmips_port_set_output (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_OUT + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_OUT); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_output); - -int -ifxmips_port_clear_output (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_OUT + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_OUT); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_clear_output); - -int -ifxmips_port_get_input (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - - if (readl(IFXMIPS_GPIO_P0_IN + (port * 0x30)) & (1 << pin)) - return 0; - else - return 1; -} -EXPORT_SYMBOL(ifxmips_port_get_input); - -int -ifxmips_port_set_altsel0 (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_ALTSEL0 + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_ALTSEL0); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_altsel0); - -int -ifxmips_port_clear_altsel0 (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_ALTSEL0 + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_ALTSEL0); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_clear_altsel0); - -int -ifxmips_port_set_altsel1 (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_ALTSEL1 + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_ALTSEL1); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_set_altsel1); - -int -ifxmips_port_clear_altsel1 (unsigned int port, unsigned int pin) -{ - IFXMIPS_GPIO_SANITY; - writel(readl(IFXMIPS_GPIO_P0_ALTSEL1 + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_ALTSEL1); - - return 0; -} -EXPORT_SYMBOL(ifxmips_port_clear_altsel1); - -long ifxmips_port_read_procmem_helper(char* tag, u32* in_reg, char *buf) -{ - u32 reg, bit = 0; - unsigned int len, t; - - len = sprintf(buf, "\n%s: ", tag); - reg = readl(in_reg); - bit = 0x80000000; - for (t = 0; t < 32; t++) { - if ((reg & bit) > 0) - len = len + sprintf(buf + len, "X"); - else - len = len + sprintf(buf + len, " "); - bit = bit >> 1; - } - - return len; -} - -int -ifxmips_port_read_procmem (char *buf, char **start, off_t offset, int count, - int *eof, void *data) -{ - long len = sprintf (buf, "\nIFXMips Port Settings\n"); - - len += sprintf (buf + len, - " 3 2 1 0\n"); - len += sprintf (buf + len, - " 10987654321098765432109876543210\n"); - len += sprintf (buf + len, - "----------------------------------------\n"); - - len += ifxmips_port_read_procmem_helper("P0-OUT", IFXMIPS_GPIO_P0_OUT, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-OUT", IFXMIPS_GPIO_P1_OUT, &buf[len]); - len += ifxmips_port_read_procmem_helper("P0-IN ", IFXMIPS_GPIO_P0_IN, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-IN ", IFXMIPS_GPIO_P1_IN, &buf[len]); - len += ifxmips_port_read_procmem_helper("P0-DIR", IFXMIPS_GPIO_P0_DIR, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-DIR", IFXMIPS_GPIO_P1_DIR, &buf[len]); - len += ifxmips_port_read_procmem_helper("P0-STO ", IFXMIPS_GPIO_P0_STOFF, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-STO ", IFXMIPS_GPIO_P1_STOFF, &buf[len]); - len += ifxmips_port_read_procmem_helper("P0-PUDE", IFXMIPS_GPIO_P0_PUDEN, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-PUDE", IFXMIPS_GPIO_P1_PUDEN, &buf[len]); - len += ifxmips_port_read_procmem_helper("P0-OD ", IFXMIPS_GPIO_P0_OD, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-OD ", IFXMIPS_GPIO_P1_OD, &buf[len]); - len += ifxmips_port_read_procmem_helper("P0-PUDS", IFXMIPS_GPIO_P0_PUDSEL, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-PUDS", IFXMIPS_GPIO_P1_PUDSEL, &buf[len]); - len += ifxmips_port_read_procmem_helper("P0-ALT0", IFXMIPS_GPIO_P0_ALTSEL0, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-ALT0", IFXMIPS_GPIO_P1_ALTSEL0, &buf[len]); - len += ifxmips_port_read_procmem_helper("P0-ALT1", IFXMIPS_GPIO_P0_ALTSEL1, &buf[len]); - len += ifxmips_port_read_procmem_helper("P1-ALT1", IFXMIPS_GPIO_P1_ALTSEL1, &buf[len]); - len = len + sprintf (buf + len, "\n\n"); - - *eof = 1; - - return len; -} - -static int -ifxmips_port_open (struct inode *inode, struct file *filep) -{ - return 0; -} - -static int -ifxmips_port_release (struct inode *inode, struct file *filelp) -{ - return 0; -} - -static int -ifxmips_port_ioctl (struct inode *inode, struct file *filp, - unsigned int cmd, unsigned long arg) -{ - int ret = 0; - volatile struct ifxmips_port_ioctl_parm parm; - - if (_IOC_TYPE (cmd) != IFXMIPS_PORT_IOC_MAGIC) - return -EINVAL; - - if (_IOC_DIR (cmd) & _IOC_WRITE) { - if (!access_ok - (VERIFY_READ, arg, - sizeof (struct ifxmips_port_ioctl_parm))) - return -EFAULT; - ret = copy_from_user ((void *) &parm, (void *) arg, - sizeof (struct ifxmips_port_ioctl_parm)); - } - if (_IOC_DIR (cmd) & _IOC_READ) { - if (!access_ok - (VERIFY_WRITE, arg, - sizeof (struct ifxmips_port_ioctl_parm))) - return -EFAULT; - } - - if (down_trylock (&port_sem) != 0) - return -EBUSY; - - switch (cmd) { - case IFXMIPS_PORT_IOCOD: - if (parm.value == 0x00) - ifxmips_port_clear_open_drain(parm.port, parm.pin); - else - ifxmips_port_set_open_drain(parm.port, parm.pin); - break; - - case IFXMIPS_PORT_IOCPUDSEL: - if (parm.value == 0x00) - ifxmips_port_clear_pudsel(parm.port, parm.pin); - else - ifxmips_port_set_pudsel(parm.port, parm.pin); - break; - - case IFXMIPS_PORT_IOCPUDEN: - if (parm.value == 0x00) - ifxmips_port_clear_puden(parm.port, parm.pin); - else - ifxmips_port_set_puden(parm.port, parm.pin); - break; - - case IFXMIPS_PORT_IOCSTOFF: - if (parm.value == 0x00) - ifxmips_port_clear_stoff(parm.port, parm.pin); - else - ifxmips_port_set_stoff(parm.port, parm.pin); - break; - - case IFXMIPS_PORT_IOCDIR: - if (parm.value == 0x00) - ifxmips_port_set_dir_in(parm.port, parm.pin); - else - ifxmips_port_set_dir_out(parm.port, parm.pin); - break; - - case IFXMIPS_PORT_IOCOUTPUT: - if (parm.value == 0x00) - ifxmips_port_clear_output(parm.port, parm.pin); - else - ifxmips_port_set_output(parm.port, parm.pin); - break; - - case IFXMIPS_PORT_IOCALTSEL0: - if (parm.value == 0x00) - ifxmips_port_clear_altsel0(parm.port, parm.pin); - else - ifxmips_port_set_altsel0(parm.port, parm.pin); - break; - - case IFXMIPS_PORT_IOCALTSEL1: - if (parm.value == 0x00) - ifxmips_port_clear_altsel1(parm.port, parm.pin); - else - ifxmips_port_set_altsel1(parm.port, parm.pin); - break; - - case IFXMIPS_PORT_IOCINPUT: - parm.value = ifxmips_port_get_input(parm.port, parm.pin); - copy_to_user((void*)arg, (void*)&parm, - sizeof(struct ifxmips_port_ioctl_parm)); - break; - - default: - ret = -EINVAL; - } - - up (&port_sem); - - return ret; -} - -static struct file_operations port_fops = { - .open = ifxmips_port_open, - .release = ifxmips_port_release, - .ioctl = ifxmips_port_ioctl -}; - -int __init -ifxmips_gpio_init (void) -{ - int retval = 0; - - sema_init (&port_sem, 1); - - ifxmips_gpio_major = register_chrdev(0, "ifxmips_gpio", &port_fops); - if (!ifxmips_gpio_major) - { - printk("ifxmips-port: Error! Could not register port device. #%d\n", ifxmips_gpio_major); - retval = -EINVAL; - goto out; - } - - create_proc_read_entry("ifxmips_gpio", 0, NULL, - ifxmips_port_read_procmem, NULL); - - printk("registered ifxmips gpio driver\n"); - -out: - return retval; -} - -void __exit -ifxmips_gpio_exit (void) -{ - unregister_chrdev(ifxmips_gpio_major, "ifxmips_gpio"); - remove_proc_entry("ifxmips_gpio", NULL); -} - -module_init(ifxmips_gpio_init); -module_exit(ifxmips_gpio_exit); diff --git a/target/linux/ifxmips/files/drivers/char/danube_led.c b/target/linux/ifxmips/files/drivers/char/danube_led.c deleted file mode 100644 index b0b8e82899..0000000000 --- a/target/linux/ifxmips/files/drivers/char/danube_led.c +++ /dev/null @@ -1,197 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) 2006 infineon - * Copyright (C) 2007 John Crispin - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define IFXMIPS_LED_CLK_EDGE IFXMIPS_LED_FALLING -//#define IFXMIPS_LED_CLK_EDGE IFXMIPS_LED_RISING - -#define IFXMIPS_LED_SPEED IFXMIPS_LED_8HZ - -#define IFXMIPS_LED_GPIO_PORT 0 - -static int ifxmips_led_major; - -void -ifxmips_led_set (unsigned int led) -{ - led &= 0xffffff; - writel(readl(IFXMIPS_LED_CPU0) | led, IFXMIPS_LED_CPU0); -} -EXPORT_SYMBOL(ifxmips_led_set); - -void -ifxmips_led_clear (unsigned int led) -{ - led = ~(led & 0xffffff); - writel(readl(IFXMIPS_LED_CPU0) & led, IFXMIPS_LED_CPU0); -} -EXPORT_SYMBOL(ifxmips_led_clear); - -void -ifxmips_led_blink_set (unsigned int led) -{ - led &= 0xffffff; - writel(readl(IFXMIPS_LED_CON0) | led, IFXMIPS_LED_CON0); -} -EXPORT_SYMBOL(ifxmips_led_blink_set); - -void -ifxmips_led_blink_clear (unsigned int led) -{ - led = ~(led & 0xffffff); - writel(readl(IFXMIPS_LED_CON0) & led, IFXMIPS_LED_CON0); -} -EXPORT_SYMBOL(ifxmips_led_blink_clear); - -void -ifxmips_led_setup_gpio (void) -{ - int i = 0; - - /* we need to setup pins SH,D,ST (4,5,6) */ - for (i = 4; i < 7; i++) - { - ifxmips_port_set_altsel0(IFXMIPS_LED_GPIO_PORT, i); - ifxmips_port_clear_altsel1(IFXMIPS_LED_GPIO_PORT, i); - ifxmips_port_set_dir_out(IFXMIPS_LED_GPIO_PORT, i); - ifxmips_port_set_open_drain(IFXMIPS_LED_GPIO_PORT, i); - } -} - -static int -led_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) -{ - int ret = -EINVAL; - - switch ( cmd ) - { - } - - return ret; -} - -static int -led_open (struct inode *inode, struct file *file) -{ - return 0; -} - -static int -led_release (struct inode *inode, struct file *file) -{ - return 0; -} - -static struct file_operations ifxmips_led_fops = { - .owner = THIS_MODULE, - .ioctl = led_ioctl, - .open = led_open, - .release = led_release -}; - - -/* -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 -*/ - - -int __init -ifxmips_led_init (void) -{ - int ret = 0; - - ifxmips_led_setup_gpio(); - - writel(0, IFXMIPS_LED_AR); - writel(0, IFXMIPS_LED_CPU0); - writel(0, IFXMIPS_LED_CPU1); - writel(LED_CON0_SWU, IFXMIPS_LED_CON0); - writel(0, IFXMIPS_LED_CON1); - - /* setup the clock edge that the shift register is triggered on */ - writel(readl(IFXMIPS_LED_CON0) & ~IFXMIPS_LED_EDGE_MASK, IFXMIPS_LED_CON0); - writel(readl(IFXMIPS_LED_CON0) | IFXMIPS_LED_CLK_EDGE, IFXMIPS_LED_CON0); - - /* per default leds 15-0 are set */ - writel(IFXMIPS_LED_GROUP1 | IFXMIPS_LED_GROUP0, IFXMIPS_LED_CON1); - - /* leds are update periodically by the FPID */ - writel(readl(IFXMIPS_LED_CON1) & ~IFXMIPS_LED_UPD_MASK, IFXMIPS_LED_CON1); - writel(readl(IFXMIPS_LED_CON1) | IFXMIPS_LED_UPD_SRC_FPI, IFXMIPS_LED_CON1); - - /* set led update speed */ - writel(readl(IFXMIPS_LED_CON1) & ~IFXMIPS_LED_MASK, IFXMIPS_LED_CON1); - writel(readl(IFXMIPS_LED_CON1) | IFXMIPS_LED_SPEED, IFXMIPS_LED_CON1); - - /* adsl 0 and 1 leds are updated by the arc */ - writel(readl(IFXMIPS_LED_CON0) | IFXMIPS_LED_ADSL_SRC, IFXMIPS_LED_CON0); - - /* per default, the leds are turned on */ - ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_LED); - - ifxmips_led_major = register_chrdev(0, "ifxmips_led", &ifxmips_led_fops); - - if (!ifxmips_led_major) - { - printk("ifxmips_led: Error! Could not register device. %d\n", ifxmips_led_major); - ret = -EINVAL; - - goto out; - } - - printk(KERN_INFO "ifxmips_led : device registered on major %d\n", ifxmips_led_major); - -out: - return ret; -} - -void __exit -ifxmips_led_exit (void) -{ - unregister_chrdev(ifxmips_led_major, "ifxmips_led"); -} - -module_init(ifxmips_led_init); -module_exit(ifxmips_led_exit); diff --git a/target/linux/ifxmips/files/drivers/char/danube_ssc.c b/target/linux/ifxmips/files/drivers/char/danube_ssc.c deleted file mode 100644 index 495f2582fa..0000000000 --- a/target/linux/ifxmips/files/drivers/char/danube_ssc.c +++ /dev/null @@ -1,1533 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) 2006 infineon - * Copyright (C) 2007 John Crispin - * - */ - -// ### TO DO: general issues: -// - power management -// - interrupt handling (direct/indirect) -// - pin/mux-handling (just overall concept due to project dependency) -// - multiple instances capability -// - slave functionality - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#ifdef SSC_FRAME_INT_ENABLE -#undef SSC_FRAME_INT_ENABLE -#endif - -#define not_yet - -#define SPI_VINETIC - - - -/* allow the user to set the major device number */ -static int maj = 0; - -/* - * This is the per-channel data structure containing pointers, flags - * and variables for the port. This driver supports a maximum of PORT_CNT. - * isp is allocated in ifx_ssc_init() based on the chip version. - */ -static struct ifx_ssc_port *isp; - -/* prototypes for fops */ -static ssize_t ifx_ssc_read (struct file *, char *, size_t, loff_t *); -static ssize_t ifx_ssc_write (struct file *, const char *, size_t, loff_t *); -//static unsigned int ifx_ssc_poll(struct file *, struct poll_table_struct *); -int ifx_ssc_ioctl (struct inode *, struct file *, unsigned int, - unsigned long); -int ifx_ssc_open (struct inode *, struct file *); -int ifx_ssc_close (struct inode *, struct file *); - -/* other forward declarations */ -static unsigned int ifx_ssc_get_kernel_clk (struct ifx_ssc_port *info); -static void tx_int (struct ifx_ssc_port *); -static int ifx_ssc1_read_proc (char *, char **, off_t, int, int *, void *); - -extern unsigned int ifxmips_get_fpi_hz (void); -extern void mask_and_ack_ifxmips_irq (unsigned int irq_nr); - -static struct file_operations ifx_ssc_fops = { - .owner = THIS_MODULE, - .read = ifx_ssc_read, - .write = ifx_ssc_write, - .ioctl = ifx_ssc_ioctl, - .open = ifx_ssc_open, - .release = ifx_ssc_close, -}; - -static inline unsigned int -ifx_ssc_get_kernel_clk (struct ifx_ssc_port *info) -{ - unsigned int rmc; - - rmc = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_CLC) & IFX_CLC_RUN_DIVIDER_MASK) >> IFX_CLC_RUN_DIVIDER_OFFSET; - if (rmc == 0) - { - printk ("ifx_ssc_get_kernel_clk rmc==0 \n"); - return 0; - } - return ifxmips_get_fpi_hz () / rmc; -} - -#ifndef not_yet -#ifdef IFX_SSC_INT_USE_BH -/* - * This routine is used by the interrupt handler to schedule - * processing in the software interrupt portion of the driver - * (also known as the "bottom half"). This can be called any - * number of times for any channel without harm. - */ -static inline void -ifx_ssc_sched_event (struct ifx_ssc_port *info, int event) -{ - info->event |= 1 << event; /* remember what kind of event and who */ - queue_task (&info->tqueue, &tq_cyclades); /* it belongs to */ - mark_bh (CYCLADES_BH); /* then trigger event */ -} - -static void -do_softint (void *private_) -{ - struct ifx_ssc_port *info = (struct ifx_ssc_port *) private_; - - if (test_and_clear_bit (Cy_EVENT_HANGUP, &info->event)) - { - wake_up_interruptible (&info->open_wait); - info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); - } - - if (test_and_clear_bit (Cy_EVENT_OPEN_WAKEUP, &info->event)) - wake_up_interruptible (&info->open_wait); - - if (test_and_clear_bit (Cy_EVENT_DELTA_WAKEUP, &info->event)) - wake_up_interruptible (&info->delta_msr_wait); - - if (test_and_clear_bit (Cy_EVENT_WRITE_WAKEUP, &info->event)) - wake_up_interruptible (&tty->write_wait); -#ifdef Z_WAKE - if (test_and_clear_bit (Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) - wake_up_interruptible (&info->shutdown_wait); -#endif -} -#endif -#endif - -inline static void -rx_int (struct ifx_ssc_port *info) -{ - int fifo_fill_lev, bytes_in_buf, i; - unsigned long tmp_val; - unsigned long *tmp_ptr; - unsigned int rx_valid_cnt; - /* number of words waiting in the RX FIFO */ - fifo_fill_lev = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_FSTAT) & IFX_SSC_FSTAT_RECEIVED_WORDS_MASK) >> IFX_SSC_FSTAT_RECEIVED_WORDS_OFFSET; - // Note: There are always 32 bits in a fifo-entry except for the last - // word of a contigous transfer block and except for not in rx-only - // mode and CON.ENBV set. But for this case it should be a convention - // in software which helps: - // In tx or rx/tx mode all transfers from the buffer to the FIFO are - // 32-bit wide, except for the last three bytes, which could be a - // combination of 16- and 8-bit access. - // => The whole block is received as 32-bit words as a contigous stream, - // even if there was a gap in tx which has the fifo run out of data! - // Just the last fifo entry *may* be partially filled (0, 1, 2 or 3 bytes)! - - /* free space in the RX buffer */ - bytes_in_buf = info->rxbuf_end - info->rxbuf_ptr; - // transfer with 32 bits per entry - while ((bytes_in_buf >= 4) && (fifo_fill_lev > 0)) { - tmp_ptr = (unsigned long *) info->rxbuf_ptr; - *tmp_ptr = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RB); - info->rxbuf_ptr += 4; - info->stats.rxBytes += 4; - fifo_fill_lev--; - bytes_in_buf -= 4; - } - - // now do the rest as mentioned in STATE.RXBV - while ((bytes_in_buf > 0) && (fifo_fill_lev > 0)) { - rx_valid_cnt = (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_RX_BYTE_VALID_MASK) >> IFX_SSC_STATE_RX_BYTE_VALID_OFFSET; - if (rx_valid_cnt == 0) - break; - - if (rx_valid_cnt > bytes_in_buf) - rx_valid_cnt = bytes_in_buf; - - tmp_val = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RB); - - for (i = 0; i < rx_valid_cnt; i++) - { - *info->rxbuf_ptr = (tmp_val >> (8 * (rx_valid_cnt - i - 1))) & 0xff; - bytes_in_buf--; - info->rxbuf_ptr++; - } - info->stats.rxBytes += rx_valid_cnt; - } - - // check if transfer is complete - if (info->rxbuf_ptr >= info->rxbuf_end) - { - disable_irq(info->rxirq); - wake_up_interruptible (&info->rwait); - } else if ((info->opts.modeRxTx == IFX_SSC_MODE_RX) && (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RXCNT) == 0)) - { - if (info->rxbuf_end - info->rxbuf_ptr < IFX_SSC_RXREQ_BLOCK_SIZE) - WRITE_PERIPHERAL_REGISTER ((info->rxbuf_end - info->rxbuf_ptr) << IFX_SSC_RXREQ_RXCOUNT_OFFSET, info->mapbase + IFX_SSC_RXREQ); - else - WRITE_PERIPHERAL_REGISTER (IFX_SSC_RXREQ_BLOCK_SIZE << IFX_SSC_RXREQ_RXCOUNT_OFFSET, info->mapbase + IFX_SSC_RXREQ); - } -} - -inline static void -tx_int (struct ifx_ssc_port *info) -{ - - int fifo_space, fill, i; - fifo_space = ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_ID) & IFX_SSC_PERID_TXFS_MASK) >> IFX_SSC_PERID_TXFS_OFFSET) - - ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_FSTAT) & IFX_SSC_FSTAT_TRANSMIT_WORDS_MASK) >> IFX_SSC_FSTAT_TRANSMIT_WORDS_OFFSET); - - if (fifo_space == 0) - return; - - fill = info->txbuf_end - info->txbuf_ptr; - - if (fill > fifo_space * 4) - fill = fifo_space * 4; - - for (i = 0; i < fill / 4; i++) - { - // at first 32 bit access - WRITE_PERIPHERAL_REGISTER (*(UINT32 *) info->txbuf_ptr, info->mapbase + IFX_SSC_TB); - info->txbuf_ptr += 4; - } - - fifo_space -= fill / 4; - info->stats.txBytes += fill & ~0x3; - fill &= 0x3; - if ((fifo_space > 0) & (fill > 1)) - { - // trailing 16 bit access - WRITE_PERIPHERAL_REGISTER_16 (*(UINT16 *) info->txbuf_ptr, info->mapbase + IFX_SSC_TB); - info->txbuf_ptr += 2; - info->stats.txBytes += 2; - fifo_space--; - fill -= 2; - } - - if ((fifo_space > 0) & (fill > 0)) - { - // trailing 8 bit access - WRITE_PERIPHERAL_REGISTER_8 (*(UINT8 *) info->txbuf_ptr, info->mapbase + IFX_SSC_TB); - info->txbuf_ptr++; - info->stats.txBytes++; - } - - // check if transmission complete - if (info->txbuf_ptr >= info->txbuf_end) - { - disable_irq(info->txirq); - kfree (info->txbuf); - info->txbuf = NULL; - } - -} - -irqreturn_t -ifx_ssc_rx_int (int irq, void *dev_id) -{ - struct ifx_ssc_port *info = (struct ifx_ssc_port *) dev_id; - rx_int (info); - - return IRQ_HANDLED; -} - -irqreturn_t -ifx_ssc_tx_int (int irq, void *dev_id) -{ - struct ifx_ssc_port *info = (struct ifx_ssc_port *) dev_id; - tx_int (info); - - return IRQ_HANDLED; -} - -irqreturn_t -ifx_ssc_err_int (int irq, void *dev_id) -{ - struct ifx_ssc_port *info = (struct ifx_ssc_port *) dev_id; - unsigned int state; - unsigned int write_back = 0; - unsigned long flags; - - local_irq_save (flags); - state = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE); - - if ((state & IFX_SSC_STATE_RX_UFL) != 0) { - info->stats.rxUnErr++; - write_back |= IFX_SSC_WHBSTATE_CLR_RX_UFL_ERROR; - } - - if ((state & IFX_SSC_STATE_RX_OFL) != 0) { - info->stats.rxOvErr++; - write_back |= IFX_SSC_WHBSTATE_CLR_RX_OFL_ERROR; - } - - if ((state & IFX_SSC_STATE_TX_OFL) != 0) { - info->stats.txOvErr++; - write_back |= IFX_SSC_WHBSTATE_CLR_TX_OFL_ERROR; - } - - if ((state & IFX_SSC_STATE_TX_UFL) != 0) { - info->stats.txUnErr++; - write_back |= IFX_SSC_WHBSTATE_CLR_TX_UFL_ERROR; - } - - if ((state & IFX_SSC_STATE_MODE_ERR) != 0) { - info->stats.modeErr++; - write_back |= IFX_SSC_WHBSTATE_CLR_MODE_ERROR; - } - - if (write_back) - WRITE_PERIPHERAL_REGISTER (write_back, info->mapbase + IFX_SSC_WHBSTATE); - - local_irq_restore (flags); - - return IRQ_HANDLED; -} - -static void -ifx_ssc_abort (struct ifx_ssc_port *info) -{ - unsigned long flags; - bool enabled; - - local_irq_save (flags); - - disable_irq(info->rxirq); - disable_irq(info->txirq); - disable_irq(info->errirq); - - local_irq_restore (flags); - - // disable SSC (also aborts a receive request!) - // ### TO DO: Perhaps it's better to abort after the receiption of a - // complete word. The disable cuts the transmission immediatly and - // releases the chip selects. This could result in unpredictable - // behavior of connected external devices! - enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_ENABLED) != 0; - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); - - // flush fifos - WRITE_PERIPHERAL_REGISTER (IFX_SSC_XFCON_FIFO_FLUSH, info->mapbase + IFX_SSC_TXFCON); - WRITE_PERIPHERAL_REGISTER (IFX_SSC_XFCON_FIFO_FLUSH, info->mapbase + IFX_SSC_RXFCON); - - // free txbuf - if (info->txbuf != NULL) - { - kfree (info->txbuf); - info->txbuf = NULL; - } - - // wakeup read process - if (info->rxbuf != NULL) - wake_up_interruptible (&info->rwait); - - // clear pending int's - mask_and_ack_ifxmips_irq(info->rxirq); - mask_and_ack_ifxmips_irq(info->txirq); - mask_and_ack_ifxmips_irq(info->errirq); - - // clear error flags - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ALL_ERROR, info->mapbase + IFX_SSC_WHBSTATE); - - if (enabled) - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); - -} - -/* - * This routine is called whenever a port is opened. It enforces - * exclusive opening of a port and enables interrupts, etc. - */ -int -ifx_ssc_open (struct inode *inode, struct file *filp) -{ - struct ifx_ssc_port *info; - int line; - int from_kernel = 0; - - if ((inode == (struct inode *) 0) || (inode == (struct inode *) 1)) { - from_kernel = 1; - line = (int) inode; - } else { - line = MINOR (filp->f_dentry->d_inode->i_rdev); - filp->f_op = &ifx_ssc_fops; - } - - /* don't open more minor devices than we can support */ - if (line < 0 || line >= PORT_CNT) - return -ENXIO; - - info = &isp[line]; - - /* exclusive open */ - if (info->port_is_open != 0) - return -EBUSY; - info->port_is_open++; - - disable_irq(info->rxirq); - disable_irq(info->txirq); - disable_irq(info->errirq); - - /* Flush and enable TX/RX FIFO */ - WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_TXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_FLUSH | IFX_SSC_XFCON_FIFO_ENABLE, info->mapbase + IFX_SSC_TXFCON); - WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_RXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_FLUSH | IFX_SSC_XFCON_FIFO_ENABLE, info->mapbase + IFX_SSC_RXFCON); - - /* logically flush the software FIFOs */ - info->rxbuf_ptr = 0; - info->txbuf_ptr = 0; - - /* clear all error bits */ - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ALL_ERROR, info->mapbase + IFX_SSC_WHBSTATE); - - // clear pending interrupts - mask_and_ack_ifxmips_irq(info->rxirq); - mask_and_ack_ifxmips_irq(info->txirq); - mask_and_ack_ifxmips_irq(info->errirq); - - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); - - return 0; -} -EXPORT_SYMBOL(ifx_ssc_open); - -int -ifx_ssc_close (struct inode *inode, struct file *filp) -{ - struct ifx_ssc_port *info; - int idx; - - if ((inode == (struct inode *) 0) || (inode == (struct inode *) 1)) - idx = (int) inode; - else - idx = MINOR (filp->f_dentry->d_inode->i_rdev); - - if (idx < 0 || idx >= PORT_CNT) - return -ENXIO; - - info = &isp[idx]; - if (!info) - return -ENXIO; - - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); - - ifx_ssc_abort(info); - - info->port_is_open--; - - return 0; -} -EXPORT_SYMBOL(ifx_ssc_close); - -static ssize_t -ifx_ssc_read_helper_poll (struct ifx_ssc_port *info, char *buf, size_t len, int from_kernel) -{ - ssize_t ret_val; - unsigned long flags; - - if (info->opts.modeRxTx == IFX_SSC_MODE_TX) - return -EFAULT; - local_irq_save (flags); - info->rxbuf_ptr = info->rxbuf; - info->rxbuf_end = info->rxbuf + len; - local_irq_restore (flags); - /* Vinetic driver always works in IFX_SSC_MODE_RXTX */ - /* TXRX in poll mode */ - while (info->rxbuf_ptr < info->rxbuf_end) - { - if (info->txbuf_ptr < info->txbuf_end) - tx_int (info); - - rx_int (info); - }; - - ret_val = info->rxbuf_ptr - info->rxbuf; - - return ret_val; -} - -static ssize_t -ifx_ssc_read_helper (struct ifx_ssc_port *info, char *buf, size_t len, int from_kernel) -{ - ssize_t ret_val; - unsigned long flags; - DECLARE_WAITQUEUE (wait, current); - - if (info->opts.modeRxTx == IFX_SSC_MODE_TX) - return -EFAULT; - - local_irq_save (flags); - info->rxbuf_ptr = info->rxbuf; - info->rxbuf_end = info->rxbuf + len; - - if (info->opts.modeRxTx == IFX_SSC_MODE_RXTX) - { - if ((info->txbuf == NULL) || (info->txbuf != info->txbuf_ptr) || (info->txbuf_end != len + info->txbuf)) - { - local_irq_restore (flags); - printk ("IFX SSC - %s: write must be called before calling " "read in combined RX/TX!\n", __func__); - return -EFAULT; - } - - local_irq_restore(flags); - tx_int (info); - - if (info->txbuf_ptr < info->txbuf_end) - enable_irq(info->txirq); - - enable_irq(info->rxirq); - } else { - local_irq_restore(flags); - if (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RXCNT) & IFX_SSC_RXCNT_TODO_MASK) - return -EBUSY; - enable_irq(info->rxirq); - if (len < IFX_SSC_RXREQ_BLOCK_SIZE) - WRITE_PERIPHERAL_REGISTER (len << IFX_SSC_RXREQ_RXCOUNT_OFFSET, info->mapbase + IFX_SSC_RXREQ); - else - WRITE_PERIPHERAL_REGISTER (IFX_SSC_RXREQ_BLOCK_SIZE << IFX_SSC_RXREQ_RXCOUNT_OFFSET, info->mapbase + IFX_SSC_RXREQ); - } - - __add_wait_queue (&info->rwait, &wait); - set_current_state (TASK_INTERRUPTIBLE); - - do { - local_irq_save (flags); - if (info->rxbuf_ptr >= info->rxbuf_end) - break; - - local_irq_restore (flags); - - if (signal_pending (current)) - { - ret_val = -ERESTARTSYS; - goto out; - } - schedule(); - } while (1); - - ret_val = info->rxbuf_ptr - info->rxbuf; - local_irq_restore (flags); - -out: - current->state = TASK_RUNNING; - __remove_wait_queue (&info->rwait, &wait); - - return (ret_val); -} - -static ssize_t -ifx_ssc_write_helper (struct ifx_ssc_port *info, const char *buf, - size_t len, int from_kernel) -{ - if (info->opts.modeRxTx == IFX_SSC_MODE_RX) - return -EFAULT; - - info->txbuf_ptr = info->txbuf; - info->txbuf_end = len + info->txbuf; - if (info->opts.modeRxTx == IFX_SSC_MODE_TX) - { - tx_int (info); - if (info->txbuf_ptr < info->txbuf_end) - { - enable_irq(info->txirq); - } - } - - return len; -} - -ssize_t -ifx_ssc_kread (int port, char *kbuf, size_t len) -{ - struct ifx_ssc_port *info; - ssize_t ret_val; - - if (port < 0 || port >= PORT_CNT) - return -ENXIO; - - if (len == 0) - return 0; - - info = &isp[port]; - - if (info->rxbuf != NULL) - { - printk ("SSC device busy\n"); - return -EBUSY; - } - - info->rxbuf = kbuf; - if (info->rxbuf == NULL) - { - printk ("SSC device error\n"); - return -EINVAL; - } - - ret_val = ifx_ssc_read_helper_poll (info, kbuf, len, 1); - info->rxbuf = NULL; - - disable_irq(info->rxirq); - - return ret_val; -} -EXPORT_SYMBOL(ifx_ssc_kread); - -ssize_t -ifx_ssc_kwrite (int port, const char *kbuf, size_t len) -{ - struct ifx_ssc_port *info; - ssize_t ret_val; - - if (port < 0 || port >= PORT_CNT) - return -ENXIO; - - if (len == 0) - return 0; - - info = &isp[port]; - - // check if transmission in progress - if (info->txbuf != NULL) - return -EBUSY; - - info->txbuf = (char *) kbuf; - - ret_val = ifx_ssc_write_helper (info, info->txbuf, len, 1); - - if (ret_val < 0) - info->txbuf = NULL; - - return ret_val; -} -EXPORT_SYMBOL(ifx_ssc_kwrite); - -static ssize_t -ifx_ssc_read (struct file *filp, char *ubuf, size_t len, loff_t * off) -{ - ssize_t ret_val; - int idx; - struct ifx_ssc_port *info; - - idx = MINOR (filp->f_dentry->d_inode->i_rdev); - info = &isp[idx]; - - if (info->rxbuf != NULL) - return -EBUSY; - - info->rxbuf = kmalloc (len + 3, GFP_KERNEL); - if (info->rxbuf == NULL) - return -ENOMEM; - - ret_val = ifx_ssc_read_helper (info, info->rxbuf, len, 0); - if (copy_to_user ((void *) ubuf, info->rxbuf, ret_val) != 0) - ret_val = -EFAULT; - - disable_irq(info->rxirq); - - kfree (info->rxbuf); - info->rxbuf = NULL; - - return (ret_val); -} - -static ssize_t -ifx_ssc_write (struct file *filp, const char *ubuf, size_t len, loff_t * off) -{ - int idx; - struct ifx_ssc_port *info; - int ret_val; - - if (len == 0) - return (0); - - idx = MINOR (filp->f_dentry->d_inode->i_rdev); - info = &isp[idx]; - - if (info->txbuf != NULL) - return -EBUSY; - - info->txbuf = kmalloc (len + 3, GFP_KERNEL); - if (info->txbuf == NULL) - return -ENOMEM; - - ret_val = copy_from_user (info->txbuf, ubuf, len); - if (ret_val == 0) - ret_val = ifx_ssc_write_helper (info, info->txbuf, len, 0); - else - ret_val = -EFAULT; - - if (ret_val < 0) - { - kfree (info->txbuf); - info->txbuf = NULL; - } - - return (ret_val); -} - -static struct ifx_ssc_frm_status * -ifx_ssc_frm_status_get (struct ifx_ssc_port *info) -{ - unsigned long tmp; - - tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFSTAT); - info->frm_status.DataBusy = (tmp & IFX_SSC_SFSTAT_IN_DATA) > 0; - info->frm_status.PauseBusy = (tmp & IFX_SSC_SFSTAT_IN_PAUSE) > 0; - info->frm_status.DataCount = (tmp & IFX_SSC_SFSTAT_DATA_COUNT_MASK) >> IFX_SSC_SFSTAT_DATA_COUNT_OFFSET; - info->frm_status.PauseCount = (tmp & IFX_SSC_SFSTAT_PAUSE_COUNT_MASK) >> IFX_SSC_SFSTAT_PAUSE_COUNT_OFFSET; - tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFCON); - info->frm_status.EnIntAfterData = (tmp & IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE) > 0; - info->frm_status.EnIntAfterPause = (tmp & IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE) > 0; - - return &info->frm_status; -} - - -static struct ifx_ssc_frm_opts * -ifx_ssc_frm_control_get (struct ifx_ssc_port *info) -{ - unsigned long tmp; - - tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFCON); - info->frm_opts.FrameEnable = (tmp & IFX_SSC_SFCON_SF_ENABLE) > 0; - info->frm_opts.DataLength = (tmp & IFX_SSC_SFCON_DATA_LENGTH_MASK) >> IFX_SSC_SFCON_DATA_LENGTH_OFFSET; - info->frm_opts.PauseLength = (tmp & IFX_SSC_SFCON_PAUSE_LENGTH_MASK) >> IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET; - info->frm_opts.IdleData = (tmp & IFX_SSC_SFCON_PAUSE_DATA_MASK) >> IFX_SSC_SFCON_PAUSE_DATA_OFFSET; - info->frm_opts.IdleClock = (tmp & IFX_SSC_SFCON_PAUSE_CLOCK_MASK) >> IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET; - info->frm_opts.StopAfterPause = (tmp & IFX_SSC_SFCON_STOP_AFTER_PAUSE) > 0; - - return &info->frm_opts; -} - -static int -ifx_ssc_frm_control_set (struct ifx_ssc_port *info) -{ - unsigned long tmp; - - // check parameters - if ((info->frm_opts.DataLength > IFX_SSC_SFCON_DATA_LENGTH_MAX) - || (info->frm_opts.DataLength < 1) - || (info->frm_opts.PauseLength > IFX_SSC_SFCON_PAUSE_LENGTH_MAX) - || (info->frm_opts.PauseLength < 1) - || (info->frm_opts.IdleData & ~(IFX_SSC_SFCON_PAUSE_DATA_MASK >> IFX_SSC_SFCON_PAUSE_DATA_OFFSET)) - || (info->frm_opts.IdleClock & ~(IFX_SSC_SFCON_PAUSE_CLOCK_MASK >> IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET))) - return -EINVAL; - - // read interrupt bits (they're not changed here) - tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFCON) & - (IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE | IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE); - - // set all values with respect to it's bit position (for data and pause - // length set N-1) - tmp = (info->frm_opts.DataLength - 1) << IFX_SSC_SFCON_DATA_LENGTH_OFFSET; - tmp |= (info->frm_opts.PauseLength - 1) << IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET; - tmp |= info->frm_opts.IdleData << IFX_SSC_SFCON_PAUSE_DATA_OFFSET; - tmp |= info->frm_opts.IdleClock << IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET; - tmp |= info->frm_opts.FrameEnable * IFX_SSC_SFCON_SF_ENABLE; - tmp |= info->frm_opts.StopAfterPause * IFX_SSC_SFCON_STOP_AFTER_PAUSE; - - WRITE_PERIPHERAL_REGISTER(tmp, info->mapbase + IFX_SSC_SFCON); - - return 0; -} - -static int -ifx_ssc_rxtx_mode_set (struct ifx_ssc_port *info, unsigned int val) -{ - unsigned long tmp; - - if (!(info) || (val & ~(IFX_SSC_MODE_MASK))) - return -EINVAL; - - if ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_BUSY) - || (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RXCNT) & IFX_SSC_RXCNT_TODO_MASK)) - return -EBUSY; - - tmp = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_CON) & ~(IFX_SSC_CON_RX_OFF | IFX_SSC_CON_TX_OFF)) | (val); - WRITE_PERIPHERAL_REGISTER (tmp, info->mapbase + IFX_SSC_CON); - info->opts.modeRxTx = val; - - return 0; -} - -static int -ifx_ssc_sethwopts (struct ifx_ssc_port *info) -{ - unsigned long flags, bits; - struct ifx_ssc_hwopts *opts = &info->opts; - - if ((opts->dataWidth < IFX_SSC_MIN_DATA_WIDTH) - || (opts->dataWidth > IFX_SSC_MAX_DATA_WIDTH)) - return -EINVAL; - - bits = (opts->dataWidth - 1) << IFX_SSC_CON_DATA_WIDTH_OFFSET; - bits |= IFX_SSC_CON_ENABLE_BYTE_VALID; - - if (opts->rxOvErrDetect) - bits |= IFX_SSC_CON_RX_OFL_CHECK; - if (opts->rxUndErrDetect) - bits |= IFX_SSC_CON_RX_UFL_CHECK; - if (opts->txOvErrDetect) - bits |= IFX_SSC_CON_TX_OFL_CHECK; - if (opts->txUndErrDetect) - bits |= IFX_SSC_CON_TX_UFL_CHECK; - if (opts->loopBack) - bits |= IFX_SSC_CON_LOOPBACK_MODE; - if (opts->echoMode) - bits |= IFX_SSC_CON_ECHO_MODE_ON; - if (opts->headingControl) - bits |= IFX_SSC_CON_MSB_FIRST; - if (opts->clockPhase) - bits |= IFX_SSC_CON_LATCH_THEN_SHIFT; - if (opts->clockPolarity) - bits |= IFX_SSC_CON_CLOCK_FALL; - - switch (opts->modeRxTx) - { - case IFX_SSC_MODE_TX: - bits |= IFX_SSC_CON_RX_OFF; - break; - case IFX_SSC_MODE_RX: - bits |= IFX_SSC_CON_TX_OFF; - break; - } - - local_irq_save (flags); - - WRITE_PERIPHERAL_REGISTER (bits, info->mapbase + IFX_SSC_CON); - WRITE_PERIPHERAL_REGISTER ((info->opts.gpoCs << IFX_SSC_GPOCON_ISCSB0_POS) | - (info->opts.gpoInv << IFX_SSC_GPOCON_INVOUT0_POS), info->mapbase + IFX_SSC_GPOCON); - - WRITE_PERIPHERAL_REGISTER (info->opts.gpoCs << IFX_SSC_WHBGPOSTAT_SETOUT0_POS, info->mapbase + IFX_SSC_WHBGPOSTAT); - - //master mode - if (opts->masterSelect) - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_MASTER_SELECT, info->mapbase + IFX_SSC_WHBSTATE); - else - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_MASTER_SELECT, info->mapbase + IFX_SSC_WHBSTATE); - - // init serial framing - WRITE_PERIPHERAL_REGISTER (0, info->mapbase + IFX_SSC_SFCON); - /* set up the port pins */ - //check for general requirements to switch (external) pad/pin characteristics - /* TODO: P0.9 SPI_CS4, P0.10 SPI_CS5, P 0.11 SPI_CS6, because of ASC0 */ - /* p0.15 SPI_CS1(EEPROM), P0.13 SPI_CS3, */ - /* Set p0.15 to alternative 01, others to 00 (In/OUT) */ - *(IFXMIPS_GPIO_P0_DIR) = (*IFXMIPS_GPIO_P0_DIR) | (0xA000); - *(IFXMIPS_GPIO_P0_ALTSEL0) = (((*IFXMIPS_GPIO_P0_ALTSEL0) | (0x8000)) & (~(0x2000))); - *(IFXMIPS_GPIO_P0_ALTSEL1) = (((*IFXMIPS_GPIO_P0_ALTSEL1) & (~0x8000)) & (~(0x2000))); - *(IFXMIPS_GPIO_P0_OD) = (*IFXMIPS_GPIO_P0_OD) | 0xA000; - - /* p1.6 SPI_CS2(SFLASH), p1.0 SPI_DIN, p1.1 SPI_DOUT, p1.2 SPI_CLK */ - *(IFXMIPS_GPIO_P1_DIR) = ((*IFXMIPS_GPIO_P1_DIR) | (0x46)) & (~1); - *(IFXMIPS_GPIO_P1_ALTSEL0) = ((*IFXMIPS_GPIO_P1_ALTSEL0) | (0x47)); - *(IFXMIPS_GPIO_P1_ALTSEL1) = (*IFXMIPS_GPIO_P1_ALTSEL1) & (~0x47); - *(IFXMIPS_GPIO_P1_OD) = (*IFXMIPS_GPIO_P1_OD) | 0x0046; - - /*CS3 */ - /*TODO: CS4 CS5 CS6 */ - *IFXMIPS_GPIO_P0_OUT = ((*IFXMIPS_GPIO_P0_OUT) | 0x2000); - - local_irq_restore (flags); - - return 0; -} - -static int -ifx_ssc_set_baud (struct ifx_ssc_port *info, unsigned int baud) -{ - unsigned int ifx_ssc_clock; - unsigned int br; - unsigned long flags; - bool enabled; - int retval = 0; - - ifx_ssc_clock = ifx_ssc_get_kernel_clk(info); - if (ifx_ssc_clock == 0) - { - retval = -EINVAL; - goto out; - } - - local_irq_save (flags); - - enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_ENABLED); - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); - - br = (((ifx_ssc_clock >> 1) + baud / 2) / baud) - 1; - wmb(); - - if (br > 0xffff || ((br == 0) && - ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_MASTER) == 0))) { - local_irq_restore (flags); - printk ("%s: invalid baudrate %u\n", __func__, baud); - return -EINVAL; - } - - WRITE_PERIPHERAL_REGISTER (br, info->mapbase + IFX_SSC_BR); - - if (enabled) - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); - - local_irq_restore(flags); - -out: - return retval; -} - -static int -ifx_ssc_hwinit (struct ifx_ssc_port *info) -{ - unsigned long flags; - bool enabled; - - enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_ENABLED); - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); - - if (ifx_ssc_sethwopts (info) < 0) - { - printk ("%s: setting the hardware options failed\n", __func__); - return -EINVAL; - } - - if (ifx_ssc_set_baud (info, info->baud) < 0) - { - printk ("%s: setting the baud rate failed\n", __func__); - return -EINVAL; - } - - local_irq_save (flags); - - /* TX FIFO */ - WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_TXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_ENABLE, - info->mapbase + IFX_SSC_TXFCON); - /* RX FIFO */ - WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_RXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_ENABLE, - info->mapbase + IFX_SSC_RXFCON); - - local_irq_restore (flags); - - if (enabled) - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); - - return 0; -} - -int -ifx_ssc_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) -{ - struct ifx_ssc_port *info; - int line, ret_val = 0; - unsigned long flags; - unsigned long tmp; - int from_kernel = 0; - - if ((inode == (struct inode *) 0) || (inode == (struct inode *) 1)) - { - from_kernel = 1; - line = (int) inode; - } else { - line = MINOR (filp->f_dentry->d_inode->i_rdev); - } - - if (line < 0 || line >= PORT_CNT) - return -ENXIO; - - info = &isp[line]; - - switch (cmd) - { - case IFX_SSC_STATS_READ: - /* data must be a pointer to a struct ifx_ssc_statistics */ - if (from_kernel) - memcpy ((void *) data, (void *) &info->stats, - sizeof (struct ifx_ssc_statistics)); - else if (copy_to_user ((void *) data, - (void *) &info->stats, - sizeof (struct ifx_ssc_statistics))) - ret_val = -EFAULT; - break; - case IFX_SSC_STATS_RESET: - /* just resets the statistics counters */ - memset ((void *) &info->stats, 0, - sizeof (struct ifx_ssc_statistics)); - break; - case IFX_SSC_BAUD_SET: - /* if the buffers are not empty then the port is */ - /* busy and we shouldn't change things on-the-fly! */ - if (!info->txbuf || !info->rxbuf || - (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) - & IFX_SSC_STATE_BUSY)) { - ret_val = -EBUSY; - break; - } - /* misuse flags */ - if (from_kernel) - flags = *((unsigned long *) data); - else if (copy_from_user ((void *) &flags, - (void *) data, sizeof (flags))) { - ret_val = -EFAULT; - break; - } - if (flags == 0) { - ret_val = -EINVAL; - break; - } - if (ifx_ssc_set_baud (info, flags) < 0) { - ret_val = -EINVAL; - break; - } - info->baud = flags; - break; - case IFX_SSC_BAUD_GET: - if (from_kernel) - *((unsigned int *) data) = info->baud; - else if (copy_to_user ((void *) data, - (void *) &info->baud, - sizeof (unsigned long))) - ret_val = -EFAULT; - break; - case IFX_SSC_RXTX_MODE_SET: - if (from_kernel) - tmp = *((unsigned long *) data); - else if (copy_from_user ((void *) &tmp, - (void *) data, sizeof (tmp))) { - ret_val = -EFAULT; - break; - } - ret_val = ifx_ssc_rxtx_mode_set (info, tmp); - break; - case IFX_SSC_RXTX_MODE_GET: - tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_CON) & - (~(IFX_SSC_CON_RX_OFF | IFX_SSC_CON_TX_OFF)); - if (from_kernel) - *((unsigned int *) data) = tmp; - else if (copy_to_user ((void *) data, - (void *) &tmp, sizeof (tmp))) - ret_val = -EFAULT; - break; - - case IFX_SSC_ABORT: - ifx_ssc_abort (info); - break; - - case IFX_SSC_GPO_OUT_SET: - if (from_kernel) - tmp = *((unsigned long *) data); - else if (copy_from_user ((void *) &tmp, - (void *) data, sizeof (tmp))) { - ret_val = -EFAULT; - break; - } - if (tmp > IFX_SSC_MAX_GPO_OUT) - ret_val = -EINVAL; - else - WRITE_PERIPHERAL_REGISTER - (1 << (tmp + IFX_SSC_WHBGPOSTAT_SETOUT0_POS), - info->mapbase + IFX_SSC_WHBGPOSTAT); - break; - case IFX_SSC_GPO_OUT_CLR: - if (from_kernel) - tmp = *((unsigned long *) data); - else if (copy_from_user ((void *) &tmp, - (void *) data, sizeof (tmp))) { - ret_val = -EFAULT; - break; - } - if (tmp > IFX_SSC_MAX_GPO_OUT) - ret_val = -EINVAL; - else { - WRITE_PERIPHERAL_REGISTER - (1 << (tmp + IFX_SSC_WHBGPOSTAT_CLROUT0_POS), - info->mapbase + IFX_SSC_WHBGPOSTAT); - } - break; - case IFX_SSC_GPO_OUT_GET: - tmp = READ_PERIPHERAL_REGISTER - (info->mapbase + IFX_SSC_GPOSTAT); - if (from_kernel) - *((unsigned int *) data) = tmp; - else if (copy_to_user ((void *) data, - (void *) &tmp, sizeof (tmp))) - ret_val = -EFAULT; - break; - case IFX_SSC_FRM_STATUS_GET: - ifx_ssc_frm_status_get (info); - if (from_kernel) - memcpy ((void *) data, (void *) &info->frm_status, - sizeof (struct ifx_ssc_frm_status)); - else if (copy_to_user ((void *) data, - (void *) &info->frm_status, - sizeof (struct ifx_ssc_frm_status))) - ret_val = -EFAULT; - break; - case IFX_SSC_FRM_CONTROL_GET: - ifx_ssc_frm_control_get (info); - if (from_kernel) - memcpy ((void *) data, (void *) &info->frm_opts, - sizeof (struct ifx_ssc_frm_opts)); - else if (copy_to_user ((void *) data, - (void *) &info->frm_opts, - sizeof (struct ifx_ssc_frm_opts))) - ret_val = -EFAULT; - break; - case IFX_SSC_FRM_CONTROL_SET: - if (from_kernel) - memcpy ((void *) &info->frm_opts, (void *) data, - sizeof (struct ifx_ssc_frm_opts)); - else if (copy_to_user ((void *) &info->frm_opts, - (void *) data, - sizeof (struct ifx_ssc_frm_opts))) { - ret_val = -EFAULT; - break; - } - ret_val = ifx_ssc_frm_control_set (info); - break; - case IFX_SSC_HWOPTS_SET: - /* data must be a pointer to a struct ifx_ssc_hwopts */ - /* if the buffers are not empty then the port is */ - /* busy and we shouldn't change things on-the-fly! */ - if (!info->txbuf || !info->rxbuf || - (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) - & IFX_SSC_STATE_BUSY)) { - ret_val = -EBUSY; - break; - } - if (from_kernel) - memcpy ((void *) &info->opts, (void *) data, - sizeof (struct ifx_ssc_hwopts)); - else if (copy_from_user ((void *) &info->opts, - (void *) data, - sizeof (struct ifx_ssc_hwopts))) { - ret_val = -EFAULT; - break; - } - if (ifx_ssc_hwinit (info) < 0) { - ret_val = -EIO; - } - break; - case IFX_SSC_HWOPTS_GET: - /* data must be a pointer to a struct ifx_ssc_hwopts */ - if (from_kernel) - memcpy ((void *) data, (void *) &info->opts, - sizeof (struct ifx_ssc_hwopts)); - else if (copy_to_user ((void *) data, - (void *) &info->opts, - sizeof (struct ifx_ssc_hwopts))) - ret_val = -EFAULT; - break; - default: - ret_val = -ENOIOCTLCMD; - } - - return ret_val; -} -EXPORT_SYMBOL(ifx_ssc_ioctl); - -static int -ifx_ssc1_read_proc (char *page, char **start, off_t offset, int count, int *eof, void *data) -{ - int off = 0; - unsigned long flags; - - local_save_flags(flags); - local_irq_disable(); - - off += sprintf (page + off, "Statistics for Infineon Synchronous Serial Controller SSC1\n"); - off += sprintf (page + off, "RX overflow errors %d\n", isp[0].stats.rxOvErr); - off += sprintf (page + off, "RX underflow errors %d\n", isp[0].stats.rxUnErr); - off += sprintf (page + off, "TX overflow errors %d\n", isp[0].stats.txOvErr); - off += sprintf (page + off, "TX underflow errors %d\n", isp[0].stats.txUnErr); - off += sprintf (page + off, "Abort errors %d\n", isp[0].stats.abortErr); - off += sprintf (page + off, "Mode errors %d\n", isp[0].stats.modeErr); - off += sprintf (page + off, "RX Bytes %d\n", isp[0].stats.rxBytes); - off += sprintf (page + off, "TX Bytes %d\n", isp[0].stats.txBytes); - - local_irq_restore(flags); - *eof = 1; - - return off; -} - -int __init -ifx_ssc_init (void) -{ - struct ifx_ssc_port *info; - int i, nbytes; - unsigned long flags; - int ret_val; - - ret_val = -ENOMEM; - nbytes = PORT_CNT * sizeof(struct ifx_ssc_port); - isp = (struct ifx_ssc_port*)kmalloc(nbytes, GFP_KERNEL); - - if (isp == NULL) - { - printk("%s: no memory for isp\n", __func__); - return (ret_val); - } - memset(isp, 0, nbytes); - - ret_val = -ENXIO; - if ((i = register_chrdev (maj, "ssc", &ifx_ssc_fops)) < 0) - { - printk ("Unable to register major %d for the Infineon SSC\n", maj); - if (maj == 0) - { - goto errout; - } else { - maj = 0; - if ((i = register_chrdev (maj, "ssc", &ifx_ssc_fops)) < 0) - { - printk ("Unable to register major %d for the Infineon SSC\n", maj); - goto errout; - } - } - } - - if (maj == 0) - maj = i; - - /* set default values in ifx_ssc_port */ - for (i = 0; i < PORT_CNT; i++) { - info = &isp[i]; - info->port_nr = i; - /* default values for the HwOpts */ - info->opts.AbortErrDetect = IFX_SSC_DEF_ABRT_ERR_DETECT; - info->opts.rxOvErrDetect = IFX_SSC_DEF_RO_ERR_DETECT; - info->opts.rxUndErrDetect = IFX_SSC_DEF_RU_ERR_DETECT; - info->opts.txOvErrDetect = IFX_SSC_DEF_TO_ERR_DETECT; - info->opts.txUndErrDetect = IFX_SSC_DEF_TU_ERR_DETECT; - info->opts.loopBack = IFX_SSC_DEF_LOOP_BACK; - info->opts.echoMode = IFX_SSC_DEF_ECHO_MODE; - info->opts.idleValue = IFX_SSC_DEF_IDLE_DATA; - info->opts.clockPolarity = IFX_SSC_DEF_CLOCK_POLARITY; - info->opts.clockPhase = IFX_SSC_DEF_CLOCK_PHASE; - info->opts.headingControl = IFX_SSC_DEF_HEADING_CONTROL; - info->opts.dataWidth = IFX_SSC_DEF_DATA_WIDTH; - info->opts.modeRxTx = IFX_SSC_DEF_MODE_RXTX; - info->opts.gpoCs = IFX_SSC_DEF_GPO_CS; - info->opts.gpoInv = IFX_SSC_DEF_GPO_INV; - info->opts.masterSelect = IFX_SSC_DEF_MASTERSLAVE; - info->baud = IFX_SSC_DEF_BAUDRATE; - info->rxbuf = NULL; - info->txbuf = NULL; - /* values specific to SSC1 */ - if (i == 0) { - info->mapbase = IFXMIPS_SSC1_BASE_ADDR; - info->txirq = IFXMIPS_SSC_TIR; - info->rxirq = IFXMIPS_SSC_RIR; - info->errirq = IFXMIPS_SSC_EIR; - } - - WRITE_PERIPHERAL_REGISTER (IFX_SSC_DEF_RMC << IFX_CLC_RUN_DIVIDER_OFFSET, info->mapbase + IFX_SSC_CLC); - - init_waitqueue_head (&info->rwait); - - local_irq_save (flags); - - // init serial framing register - WRITE_PERIPHERAL_REGISTER (IFX_SSC_DEF_SFCON, info->mapbase + IFX_SSC_SFCON); - - ret_val = request_irq(info->txirq, ifx_ssc_tx_int, SA_INTERRUPT, "ifx_ssc_tx", info); - if (ret_val) - { - printk("%s: unable to get irq %d\n", __func__, info->txirq); - local_irq_restore(flags); - goto errout; - } - - ret_val = request_irq(info->rxirq, ifx_ssc_rx_int, SA_INTERRUPT, "ifx_ssc_rx", info); - if (ret_val) - { - printk ("%s: unable to get irq %d\n", __func__, info->rxirq); - local_irq_restore (flags); - goto irqerr; - } - - ret_val = request_irq(info->errirq, ifx_ssc_err_int, SA_INTERRUPT,"ifx_ssc_err", info); - if (ret_val) - { - printk ("%s: unable to get irq %d\n", __func__, info->errirq); - local_irq_restore (flags); - goto irqerr; - } - WRITE_PERIPHERAL_REGISTER (IFX_SSC_DEF_IRNEN, info->mapbase + IFX_SSC_IRN_EN); - - enable_irq(info->txirq); - enable_irq(info->rxirq); - enable_irq(info->errirq); - - local_irq_restore (flags); - } - - for (i = 0; i < PORT_CNT; i++) { - info = &isp[i]; - if (ifx_ssc_hwinit (info) < 0) - { - printk ("%s: hardware init failed for port %d\n", __func__, i); - goto irqerr; - } - } - - create_proc_read_entry ("driver/ssc1", 0, NULL, ifx_ssc1_read_proc, NULL); - - return 0; - -irqerr: - free_irq(isp[0].txirq, &isp[0]); - free_irq(isp[0].rxirq, &isp[0]); - free_irq(isp[0].errirq, &isp[0]); -errout: - kfree (isp); - return (ret_val); -} - -void -ifx_ssc_cleanup_module (void) -{ - int i; - - for (i = 0; i < PORT_CNT; i++) { - WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, isp[i].mapbase + IFX_SSC_WHBSTATE); - free_irq(isp[i].txirq, &isp[i]); - free_irq(isp[i].rxirq, &isp[i]); - free_irq(isp[i].errirq, &isp[i]); - } - kfree (isp); - remove_proc_entry ("driver/ssc1", NULL); -} - -module_init(ifx_ssc_init); -module_exit(ifx_ssc_cleanup_module); - - -inline int -ifx_ssc_cs_low (u32 pin) -{ - int ret = 0; - if ((ret = ifx_ssc_ioctl ((struct inode *) 0, NULL, IFX_SSC_GPO_OUT_CLR, (unsigned long) &pin))) - printk ("clear CS %d fails\n", pin); - wmb (); - - return ret; -} -EXPORT_SYMBOL(ifx_ssc_cs_low); - -inline int -ifx_ssc_cs_high (u32 pin) -{ - int ret = 0; - if ((ret = ifx_ssc_ioctl((struct inode *) 0, NULL, IFX_SSC_GPO_OUT_SET, (unsigned long) &pin))) - printk ("set CS %d fails\n", pin); - wmb (); - - return ret; -} -EXPORT_SYMBOL(ifx_ssc_cs_high); - -static int -ssc_session (char *tx_buf, u32 tx_len, char *rx_buf, u32 rx_len) -{ - int ret = 0; - - char *ssc_tx_buf = NULL; - char *ssc_rx_buf = NULL; - int eff_size = 0; - u8 mode = 0; - - if (tx_buf == NULL && tx_len == 0 && rx_buf == NULL && rx_len == 0) { - printk ("invalid parameters\n"); - ret = -EINVAL; - goto ssc_session_exit; - } - else if (tx_buf == NULL || tx_len == 0) { - if (rx_buf != NULL && rx_len != 0) { - mode = IFX_SSC_MODE_RX; - } - else { - printk ("invalid parameters\n"); - ret = -EINVAL; - goto ssc_session_exit; - } - } - else if (rx_buf == NULL || rx_len == 0) { - if (tx_buf != NULL && tx_len != 0) { - mode = IFX_SSC_MODE_TX; - } - else { - printk ("invalid parameters\n"); - ret = -EINVAL; - goto ssc_session_exit; - } - } - else { - mode = IFX_SSC_MODE_RXTX; - } - - if (mode == IFX_SSC_MODE_RXTX) { - eff_size = tx_len + rx_len; - } - else if (mode == IFX_SSC_MODE_RX) { - eff_size = rx_len; - } - else { - eff_size = tx_len; - } - - //4 bytes alignment, required by driver - /* change by TaiCheng */ - //if (in_irq()){ - if (1) { - ssc_tx_buf = - (char *) kmalloc (sizeof (char) * - ((eff_size + 3) & (~3)), - GFP_ATOMIC); - ssc_rx_buf = - (char *) kmalloc (sizeof (char) * - ((eff_size + 3) & (~3)), - GFP_ATOMIC); - } - else { - ssc_tx_buf = - (char *) kmalloc (sizeof (char) * - ((eff_size + 3) & (~3)), - GFP_KERNEL); - ssc_rx_buf = - (char *) kmalloc (sizeof (char) * - ((eff_size + 3) & (~3)), - GFP_KERNEL); - } - if (ssc_tx_buf == NULL || ssc_rx_buf == NULL) { - printk ("no memory for size of %d\n", eff_size); - ret = -ENOMEM; - goto ssc_session_exit; - } - memset ((void *) ssc_tx_buf, 0, eff_size); - memset ((void *) ssc_rx_buf, 0, eff_size); - - if (tx_len > 0) { - memcpy (ssc_tx_buf, tx_buf, tx_len); - } - - ret = ifx_ssc_kwrite (0, ssc_tx_buf, eff_size); - - if (ret > 0) { - ssc_tx_buf = NULL; //should be freed by ifx_ssc_kwrite - } - - if (ret != eff_size) { - printk ("ifx_ssc_write return %d\n", ret); - goto ssc_session_exit; - } - ret = ifx_ssc_kread (0, ssc_rx_buf, eff_size); - if (ret != eff_size) { - printk ("ifx_ssc_read return %d\n", ret); - goto ssc_session_exit; - } - - memcpy (rx_buf, ssc_rx_buf + tx_len, rx_len); - - if (mode == IFX_SSC_MODE_TX) { - ret = tx_len; - } - else { - ret = rx_len; - } - ssc_session_exit: - - if (ssc_tx_buf != NULL) - kfree (ssc_tx_buf); - if (ssc_rx_buf != NULL) - kfree (ssc_rx_buf); - - if (ret < 0) { - printk ("ssc session fails\n"); - } - return ret; -} - -int -ifx_ssc_txrx (char *tx_buf, u32 tx_len, char *rx_buf, u32 rx_len) -{ - return ssc_session(tx_buf, tx_len, rx_buf, rx_len); -} -EXPORT_SYMBOL(ifx_ssc_txrx); - -int -ifx_ssc_tx (char *tx_buf, u32 tx_len) -{ - return ssc_session(tx_buf, tx_len, NULL, 0); -} -EXPORT_SYMBOL(ifx_ssc_tx); - -int -ifx_ssc_rx (char *rx_buf, u32 rx_len) -{ - return ssc_session(NULL, 0, rx_buf, rx_len); -} -EXPORT_SYMBOL(ifx_ssc_rx); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("John Crispin "); -MODULE_DESCRIPTION("ifxmips ssc driver"); - diff --git a/target/linux/ifxmips/files/drivers/char/ifxmips_eeprom.c b/target/linux/ifxmips/files/drivers/char/ifxmips_eeprom.c new file mode 100644 index 0000000000..ea1303cd66 --- /dev/null +++ b/target/linux/ifxmips/files/drivers/char/ifxmips_eeprom.c @@ -0,0 +1,541 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * This driver was originally based on the INCA-IP driver, but due to + * fundamental conceptual drawbacks there has been changed a lot. + * + * Based on INCA-IP driver Copyright (c) 2003 Gary Jennejohn + * Based on the VxWorks drivers Copyright (c) 2002, Infineon Technologies. + * + * Copyright (C) 2006 infineon + * Copyright (C) 2007 John Crispin + * + */ + +#define IFAP_EEPROM_DRV_VERSION "0.0.1" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +/* allow the user to set the major device number */ +static int ifxmips_eeprom_maj = 0; + +extern int ifx_ssc_init (void); +extern int ifx_ssc_open (struct inode *inode, struct file *filp); +extern int ifx_ssc_close (struct inode *inode, struct file *filp); +extern void ifx_ssc_cleanup_module (void); +extern int ifx_ssc_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long data); +extern ssize_t ifx_ssc_kwrite (int port, const char *kbuf, size_t len); +extern ssize_t ifx_ssc_kread (int port, char *kbuf, size_t len); + +extern int ifx_ssc_cs_low (unsigned int pin); +extern int ifx_ssc_cs_high (unsigned int pin); +extern int ifx_ssc_txrx (char *tx_buf, unsigned int tx_len, char *rx_buf, unsigned int rx_len); +extern int ifx_ssc_tx (char *tx_buf, unsigned int tx_len); +extern int ifx_ssc_rx (char *rx_buf, unsigned int rx_len); + +#define EEPROM_CS IFX_SSC_WHBGPOSTAT_OUT0_POS + +/* commands for EEPROM, x25160, x25140 */ +#define EEPROM_WREN ((unsigned char)0x06) +#define EEPROM_WRDI ((unsigned char)0x04) +#define EEPROM_RDSR ((unsigned char)0x05) +#define EEPROM_WRSR ((unsigned char)0x01) +#define EEPROM_READ ((unsigned char)0x03) +#define EEPROM_WRITE ((unsigned char)0x02) +#define EEPROM_PAGE_SIZE 4 +#define EEPROM_SIZE 512 + +static int +eeprom_rdsr (void) +{ + int ret = 0; + unsigned char cmd = EEPROM_RDSR; + unsigned long flag; + char status; + + local_irq_save(flag); + + if ((ret = ifx_ssc_cs_low(EEPROM_CS)) == 0) + if ((ret = ifx_ssc_txrx(&cmd, 1, &status, 1)) >= 0) + ret = status & 1; + + ifx_ssc_cs_high(EEPROM_CS); + local_irq_restore(flag); + + return ret; +} + +void +eeprom_wip_over (void) +{ + while (eeprom_rdsr()) + printk("waiting for eeprom\n"); +} + +static int +eeprom_wren (void) +{ + unsigned char cmd = EEPROM_WREN; + int ret = 0; + unsigned long flag; + + local_irq_save(flag); + if ((ret = ifx_ssc_cs_low(EEPROM_CS)) == 0) + if ((ret = ifx_ssc_tx(&cmd, 1)) >= 0) + ret = 0; + + ifx_ssc_cs_high(EEPROM_CS); + local_irq_restore(flag); + + if (!ret) + eeprom_wip_over(); + + return ret; +} + +static int +eeprom_wrsr (void) +{ + int ret = 0; + unsigned char cmd[2]; + unsigned long flag; + + cmd[0] = EEPROM_WRSR; + cmd[1] = 0; + + if ((ret = eeprom_wren())) + { + printk ("eeprom_wren fails\n"); + goto out1; + } + + local_irq_save(flag); + + if ((ret = ifx_ssc_cs_low(EEPROM_CS))) + goto out; + + if ((ret = ifx_ssc_tx(cmd, 2)) < 0) { + ifx_ssc_cs_high(EEPROM_CS); + goto out; + } + + if ((ret = ifx_ssc_cs_low(EEPROM_CS))) + goto out; + + local_irq_restore(flag); + eeprom_wip_over(); + + return ret; + +out: + local_irq_restore (flag); + eeprom_wip_over (); + +out1: + return ret; +} + +static int +eeprom_read (unsigned int addr, unsigned char *buf, unsigned int len) +{ + int ret = 0; + unsigned char write_buf[2]; + unsigned int eff = 0; + unsigned long flag; + + while (1) + { + eeprom_wip_over(); + eff = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE); + eff = (eff < len) ? eff : len; + local_irq_save(flag); + + if ((ret = ifx_ssc_cs_low(EEPROM_CS)) < 0) + goto out; + + write_buf[0] = EEPROM_READ | ((unsigned char) ((addr & 0x100) >> 5)); + write_buf[1] = (addr & 0xff); + + if ((ret = ifx_ssc_txrx (write_buf, 2, buf, eff)) != eff) + { + printk("ssc_txrx fails %d\n", ret); + ifx_ssc_cs_high (EEPROM_CS); + goto out; + } + + buf += ret; + len -= ret; + addr += ret; + + if ((ret = ifx_ssc_cs_high(EEPROM_CS))) + goto out; + + local_irq_restore(flag); + + if (len <= 0) + goto out2; + } + +out: + local_irq_restore (flag); +out2: + return ret; +} + +static int +eeprom_write (unsigned int addr, unsigned char *buf, unsigned int len) +{ + int ret = 0; + unsigned int eff = 0; + unsigned char write_buf[2]; + int i; + unsigned char rx_buf[EEPROM_PAGE_SIZE]; + + while (1) + { + eeprom_wip_over(); + + if ((ret = eeprom_wren())) + { + printk("eeprom_wren fails\n"); + goto out; + } + + write_buf[0] = EEPROM_WRITE | ((unsigned char) ((addr & 0x100) >> 5)); + write_buf[1] = (addr & 0xff); + + eff = EEPROM_PAGE_SIZE - (addr % EEPROM_PAGE_SIZE); + eff = (eff < len) ? eff : len; + + printk("EEPROM Write:\n"); + for (i = 0; i < eff; i++) { + printk("%2x ", buf[i]); + if ((i % 16) == 15) + printk("\n"); + } + printk("\n"); + + if ((ret = ifx_ssc_cs_low(EEPROM_CS))) + goto out; + + if ((ret = ifx_ssc_tx (write_buf, 2)) < 0) + { + printk("ssc_tx fails %d\n", ret); + ifx_ssc_cs_high(EEPROM_CS); + goto out; + } + + if ((ret = ifx_ssc_tx (buf, eff)) != eff) + { + printk("ssc_tx fails %d\n", ret); + ifx_ssc_cs_high(EEPROM_CS); + goto out; + } + + buf += ret; + len -= ret; + addr += ret; + + if ((ret = ifx_ssc_cs_high (EEPROM_CS))) + goto out; + + printk ("<=="); + eeprom_read((addr - eff), rx_buf, eff); + for (i = 0; i < eff; i++) + { + printk ("[%x]", rx_buf[i]); + } + printk ("\n"); + + if (len <= 0) + break; + } + +out: + return ret; +} + +int +ifxmips_eeprom_open (struct inode *inode, struct file *filp) +{ + filp->f_pos = 0; + return 0; +} + +int +ifxmips_eeprom_close (struct inode *inode, struct file *filp) +{ + return 0; +} + +int +ifxmips_eeprom_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) +{ + return 0; +} + +ssize_t +ifxmips_eeprom_read (char *buf, size_t len, unsigned int addr) +{ + int ret = 0; + unsigned int data; + + printk("addr:=%d\n", addr); + printk("len:=%d\n", len); + + if ((addr + len) > EEPROM_SIZE) + { + printk("invalid len\n"); + addr = 0; + len = EEPROM_SIZE / 2; + } + + if ((ret = ifx_ssc_open((struct inode *) 0, NULL))) + { + printk("ifxmips_eeprom_open fails\n"); + goto out; + } + + data = (unsigned int)IFX_SSC_MODE_RXTX; + + if ((ret = ifx_ssc_ioctl((struct inode *) 0, NULL, IFX_SSC_RXTX_MODE_SET, (unsigned long) &data))) + { + printk("set RXTX mode fails\n"); + goto out; + } + + if ((ret = eeprom_wrsr())) + { + printk("EEPROM reset fails\n"); + goto out; + } + + if ((ret = eeprom_read(addr, buf, len))) + { + printk("eeprom read fails\n"); + goto out; + } + +out: + if (ifx_ssc_close((struct inode *) 0, NULL)) + printk("ifxmips_eeprom_close fails\n"); + + return len; +} +EXPORT_SYMBOL(ifxmips_eeprom_read); + +static ssize_t +ifxmips_eeprom_fops_read (struct file *filp, char *ubuf, size_t len, loff_t * off) +{ + int ret = 0; + unsigned char ssc_rx_buf[EEPROM_SIZE]; + long flag; + + if (*off >= EEPROM_SIZE) + return 0; + + if (*off + len > EEPROM_SIZE) + len = EEPROM_SIZE - *off; + + if (len == 0) + return 0; + + local_irq_save(flag); + + if ((ret = ifxmips_eeprom_read(ssc_rx_buf, len, *off)) < 0) + { + printk("read fails, err=%x\n", ret); + local_irq_restore(flag); + return ret; + } + + if (copy_to_user((void*)ubuf, ssc_rx_buf, ret) != 0) + { + local_irq_restore(flag); + ret = -EFAULT; + } + + local_irq_restore(flag); + *off += len; + + return len; +} + +ssize_t +ifxmips_eeprom_write (char *buf, size_t len, unsigned int addr) +{ + int ret = 0; + unsigned int data; + + if ((ret = ifx_ssc_open ((struct inode *) 0, NULL))) + { + printk ("ifxmips_eeprom_open fails\n"); + goto out; + } + + data = (unsigned int) IFX_SSC_MODE_RXTX; + + if ((ret = ifx_ssc_ioctl ((struct inode *) 0, NULL, IFX_SSC_RXTX_MODE_SET, (unsigned long) &data))) + { + printk ("set RXTX mode fails\n"); + goto out; + } + + if ((ret = eeprom_wrsr ())) { + printk ("EEPROM reset fails\n"); + goto out; + } + + if ((ret = eeprom_write (addr, buf, len))) { + printk ("eeprom write fails\n"); + goto out; + } + +out: + if (ifx_ssc_close ((struct inode *) 0, NULL)) + printk ("ifxmips_eeprom_close fails\n"); + + return ret; +} +EXPORT_SYMBOL(ifxmips_eeprom_write); + +static ssize_t +ifxmips_eeprom_fops_write (struct file *filp, const char *ubuf, size_t len, loff_t * off) +{ + int ret = 0; + unsigned char ssc_tx_buf[EEPROM_SIZE]; + + if (*off >= EEPROM_SIZE) + return 0; + + if (len + *off > EEPROM_SIZE) + len = EEPROM_SIZE - *off; + + if ((ret = copy_from_user (ssc_tx_buf, ubuf, len))) + return EFAULT; + + ret = ifxmips_eeprom_write (ssc_tx_buf, len, *off); + + if (ret > 0) + *off = ret; + + return ret; +} + +loff_t +ifxmips_eeprom_llseek (struct file * filp, loff_t off, int whence) +{ + loff_t newpos; + switch (whence) { + case SEEK_SET: + newpos = off; + break; + + case SEEK_CUR: + newpos = filp->f_pos + off; + break; + + default: + return -EINVAL; + } + + if (newpos < 0) + return -EINVAL; + + filp->f_pos = newpos; + + return newpos; +} + +static struct file_operations ifxmips_eeprom_fops = { + owner:THIS_MODULE, + llseek:ifxmips_eeprom_llseek, + read:ifxmips_eeprom_fops_read, + write:ifxmips_eeprom_fops_write, + ioctl:ifxmips_eeprom_ioctl, + open:ifxmips_eeprom_open, + release:ifxmips_eeprom_close, +}; + +int __init +ifxmips_eeprom_init (void) +{ + int ret = 0; + + ifxmips_eeprom_maj = register_chrdev(0, "eeprom", &ifxmips_eeprom_fops); + + if (ifxmips_eeprom_maj < 0) + { + printk("failed to register eeprom device\n"); + ret = -EINVAL; + + goto out; + } + + printk("ifxmips_eeprom : /dev/eeprom mayor %d\n", ifxmips_eeprom_maj); + +out: + return ret; +} + +void __exit +ifxmips_eeprom_cleanup_module (void) +{ + /*if (unregister_chrdev (ifxmips_eeprom_maj, "eeprom")) { + printk ("Unable to unregister major %d for the EEPROM\n", + maj); + }*/ +} + +module_exit (ifxmips_eeprom_cleanup_module); +module_init (ifxmips_eeprom_init); + +MODULE_LICENSE ("GPL"); +MODULE_AUTHOR ("Peng Liu"); +MODULE_DESCRIPTION ("IFAP EEPROM driver"); +MODULE_SUPPORTED_DEVICE ("ifxmips_eeprom"); + + diff --git a/target/linux/ifxmips/files/drivers/char/ifxmips_gpio.c b/target/linux/ifxmips/files/drivers/char/ifxmips_gpio.c new file mode 100644 index 0000000000..6ac9ec6b17 --- /dev/null +++ b/target/linux/ifxmips/files/drivers/char/ifxmips_gpio.c @@ -0,0 +1,442 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2005 infineon + * Copyright (C) 2007 John Crispin + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAX_PORTS 2 +#define PINS_PER_PORT 16 + +static unsigned int ifxmips_gpio_major = 0; + +/* TODO do we need this ? */ +static struct semaphore port_sem; + +/* TODO do we really need this ? return in a define is forbidden by coding style */ +#define IFXMIPS_GPIO_SANITY {if (port > MAX_PORTS || pin > PINS_PER_PORT) return -EINVAL; } + +int +ifxmips_port_reserve_pin (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + printk("%s : call to obseleted function\n", __func__); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_reserve_pin); + +int +ifxmips_port_free_pin (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + printk("%s : call to obseleted function\n", __func__); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_free_pin); + +int +ifxmips_port_set_open_drain (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_OD + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_OD); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_open_drain); + +int +ifxmips_port_clear_open_drain (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_OD + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_OD); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_clear_open_drain); + +int +ifxmips_port_set_pudsel (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_PUDSEL + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_PUDSEL); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_pudsel); + +int +ifxmips_port_clear_pudsel (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_PUDSEL + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_PUDSEL); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_clear_pudsel); + +int +ifxmips_port_set_puden (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_PUDEN + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_PUDEN); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_puden); + +int +ifxmips_port_clear_puden (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_PUDEN + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_PUDEN); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_clear_puden); + +int +ifxmips_port_set_stoff (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_STOFF + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_STOFF); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_stoff); + +int +ifxmips_port_clear_stoff (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_STOFF + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_STOFF); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_clear_stoff); + +int +ifxmips_port_set_dir_out (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_DIR + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_DIR); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_dir_out); + +int +ifxmips_port_set_dir_in (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_DIR + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_DIR); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_dir_in); + +int +ifxmips_port_set_output (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_OUT + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_OUT); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_output); + +int +ifxmips_port_clear_output (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_OUT + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_OUT); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_clear_output); + +int +ifxmips_port_get_input (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + + if (readl(IFXMIPS_GPIO_P0_IN + (port * 0x30)) & (1 << pin)) + return 0; + else + return 1; +} +EXPORT_SYMBOL(ifxmips_port_get_input); + +int +ifxmips_port_set_altsel0 (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_ALTSEL0 + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_ALTSEL0); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_altsel0); + +int +ifxmips_port_clear_altsel0 (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_ALTSEL0 + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_ALTSEL0); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_clear_altsel0); + +int +ifxmips_port_set_altsel1 (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_ALTSEL1 + (port * 0x30)) | (1 << pin), IFXMIPS_GPIO_P0_ALTSEL1); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_set_altsel1); + +int +ifxmips_port_clear_altsel1 (unsigned int port, unsigned int pin) +{ + IFXMIPS_GPIO_SANITY; + writel(readl(IFXMIPS_GPIO_P0_ALTSEL1 + (port * 0x30)) & ~(1 << pin), IFXMIPS_GPIO_P0_ALTSEL1); + + return 0; +} +EXPORT_SYMBOL(ifxmips_port_clear_altsel1); + +long ifxmips_port_read_procmem_helper(char* tag, u32* in_reg, char *buf) +{ + u32 reg, bit = 0; + unsigned int len, t; + + len = sprintf(buf, "\n%s: ", tag); + reg = readl(in_reg); + bit = 0x80000000; + for (t = 0; t < 32; t++) { + if ((reg & bit) > 0) + len = len + sprintf(buf + len, "X"); + else + len = len + sprintf(buf + len, " "); + bit = bit >> 1; + } + + return len; +} + +int +ifxmips_port_read_procmem (char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + long len = sprintf (buf, "\nIFXMips Port Settings\n"); + + len += sprintf (buf + len, + " 3 2 1 0\n"); + len += sprintf (buf + len, + " 10987654321098765432109876543210\n"); + len += sprintf (buf + len, + "----------------------------------------\n"); + + len += ifxmips_port_read_procmem_helper("P0-OUT", IFXMIPS_GPIO_P0_OUT, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-OUT", IFXMIPS_GPIO_P1_OUT, &buf[len]); + len += ifxmips_port_read_procmem_helper("P0-IN ", IFXMIPS_GPIO_P0_IN, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-IN ", IFXMIPS_GPIO_P1_IN, &buf[len]); + len += ifxmips_port_read_procmem_helper("P0-DIR", IFXMIPS_GPIO_P0_DIR, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-DIR", IFXMIPS_GPIO_P1_DIR, &buf[len]); + len += ifxmips_port_read_procmem_helper("P0-STO ", IFXMIPS_GPIO_P0_STOFF, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-STO ", IFXMIPS_GPIO_P1_STOFF, &buf[len]); + len += ifxmips_port_read_procmem_helper("P0-PUDE", IFXMIPS_GPIO_P0_PUDEN, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-PUDE", IFXMIPS_GPIO_P1_PUDEN, &buf[len]); + len += ifxmips_port_read_procmem_helper("P0-OD ", IFXMIPS_GPIO_P0_OD, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-OD ", IFXMIPS_GPIO_P1_OD, &buf[len]); + len += ifxmips_port_read_procmem_helper("P0-PUDS", IFXMIPS_GPIO_P0_PUDSEL, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-PUDS", IFXMIPS_GPIO_P1_PUDSEL, &buf[len]); + len += ifxmips_port_read_procmem_helper("P0-ALT0", IFXMIPS_GPIO_P0_ALTSEL0, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-ALT0", IFXMIPS_GPIO_P1_ALTSEL0, &buf[len]); + len += ifxmips_port_read_procmem_helper("P0-ALT1", IFXMIPS_GPIO_P0_ALTSEL1, &buf[len]); + len += ifxmips_port_read_procmem_helper("P1-ALT1", IFXMIPS_GPIO_P1_ALTSEL1, &buf[len]); + len = len + sprintf (buf + len, "\n\n"); + + *eof = 1; + + return len; +} + +static int +ifxmips_port_open (struct inode *inode, struct file *filep) +{ + return 0; +} + +static int +ifxmips_port_release (struct inode *inode, struct file *filelp) +{ + return 0; +} + +static int +ifxmips_port_ioctl (struct inode *inode, struct file *filp, + unsigned int cmd, unsigned long arg) +{ + int ret = 0; + volatile struct ifxmips_port_ioctl_parm parm; + + if (_IOC_TYPE (cmd) != IFXMIPS_PORT_IOC_MAGIC) + return -EINVAL; + + if (_IOC_DIR (cmd) & _IOC_WRITE) { + if (!access_ok + (VERIFY_READ, arg, + sizeof (struct ifxmips_port_ioctl_parm))) + return -EFAULT; + ret = copy_from_user ((void *) &parm, (void *) arg, + sizeof (struct ifxmips_port_ioctl_parm)); + } + if (_IOC_DIR (cmd) & _IOC_READ) { + if (!access_ok + (VERIFY_WRITE, arg, + sizeof (struct ifxmips_port_ioctl_parm))) + return -EFAULT; + } + + if (down_trylock (&port_sem) != 0) + return -EBUSY; + + switch (cmd) { + case IFXMIPS_PORT_IOCOD: + if (parm.value == 0x00) + ifxmips_port_clear_open_drain(parm.port, parm.pin); + else + ifxmips_port_set_open_drain(parm.port, parm.pin); + break; + + case IFXMIPS_PORT_IOCPUDSEL: + if (parm.value == 0x00) + ifxmips_port_clear_pudsel(parm.port, parm.pin); + else + ifxmips_port_set_pudsel(parm.port, parm.pin); + break; + + case IFXMIPS_PORT_IOCPUDEN: + if (parm.value == 0x00) + ifxmips_port_clear_puden(parm.port, parm.pin); + else + ifxmips_port_set_puden(parm.port, parm.pin); + break; + + case IFXMIPS_PORT_IOCSTOFF: + if (parm.value == 0x00) + ifxmips_port_clear_stoff(parm.port, parm.pin); + else + ifxmips_port_set_stoff(parm.port, parm.pin); + break; + + case IFXMIPS_PORT_IOCDIR: + if (parm.value == 0x00) + ifxmips_port_set_dir_in(parm.port, parm.pin); + else + ifxmips_port_set_dir_out(parm.port, parm.pin); + break; + + case IFXMIPS_PORT_IOCOUTPUT: + if (parm.value == 0x00) + ifxmips_port_clear_output(parm.port, parm.pin); + else + ifxmips_port_set_output(parm.port, parm.pin); + break; + + case IFXMIPS_PORT_IOCALTSEL0: + if (parm.value == 0x00) + ifxmips_port_clear_altsel0(parm.port, parm.pin); + else + ifxmips_port_set_altsel0(parm.port, parm.pin); + break; + + case IFXMIPS_PORT_IOCALTSEL1: + if (parm.value == 0x00) + ifxmips_port_clear_altsel1(parm.port, parm.pin); + else + ifxmips_port_set_altsel1(parm.port, parm.pin); + break; + + case IFXMIPS_PORT_IOCINPUT: + parm.value = ifxmips_port_get_input(parm.port, parm.pin); + copy_to_user((void*)arg, (void*)&parm, + sizeof(struct ifxmips_port_ioctl_parm)); + break; + + default: + ret = -EINVAL; + } + + up (&port_sem); + + return ret; +} + +static struct file_operations port_fops = { + .open = ifxmips_port_open, + .release = ifxmips_port_release, + .ioctl = ifxmips_port_ioctl +}; + +int __init +ifxmips_gpio_init (void) +{ + int retval = 0; + + sema_init (&port_sem, 1); + + ifxmips_gpio_major = register_chrdev(0, "ifxmips_gpio", &port_fops); + if (!ifxmips_gpio_major) + { + printk("ifxmips-port: Error! Could not register port device. #%d\n", ifxmips_gpio_major); + retval = -EINVAL; + goto out; + } + + create_proc_read_entry("ifxmips_gpio", 0, NULL, + ifxmips_port_read_procmem, NULL); + + printk("registered ifxmips gpio driver\n"); + +out: + return retval; +} + +void __exit +ifxmips_gpio_exit (void) +{ + unregister_chrdev(ifxmips_gpio_major, "ifxmips_gpio"); + remove_proc_entry("ifxmips_gpio", NULL); +} + +module_init(ifxmips_gpio_init); +module_exit(ifxmips_gpio_exit); diff --git a/target/linux/ifxmips/files/drivers/char/ifxmips_led.c b/target/linux/ifxmips/files/drivers/char/ifxmips_led.c new file mode 100644 index 0000000000..b0b8e82899 --- /dev/null +++ b/target/linux/ifxmips/files/drivers/char/ifxmips_led.c @@ -0,0 +1,197 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2006 infineon + * Copyright (C) 2007 John Crispin + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IFXMIPS_LED_CLK_EDGE IFXMIPS_LED_FALLING +//#define IFXMIPS_LED_CLK_EDGE IFXMIPS_LED_RISING + +#define IFXMIPS_LED_SPEED IFXMIPS_LED_8HZ + +#define IFXMIPS_LED_GPIO_PORT 0 + +static int ifxmips_led_major; + +void +ifxmips_led_set (unsigned int led) +{ + led &= 0xffffff; + writel(readl(IFXMIPS_LED_CPU0) | led, IFXMIPS_LED_CPU0); +} +EXPORT_SYMBOL(ifxmips_led_set); + +void +ifxmips_led_clear (unsigned int led) +{ + led = ~(led & 0xffffff); + writel(readl(IFXMIPS_LED_CPU0) & led, IFXMIPS_LED_CPU0); +} +EXPORT_SYMBOL(ifxmips_led_clear); + +void +ifxmips_led_blink_set (unsigned int led) +{ + led &= 0xffffff; + writel(readl(IFXMIPS_LED_CON0) | led, IFXMIPS_LED_CON0); +} +EXPORT_SYMBOL(ifxmips_led_blink_set); + +void +ifxmips_led_blink_clear (unsigned int led) +{ + led = ~(led & 0xffffff); + writel(readl(IFXMIPS_LED_CON0) & led, IFXMIPS_LED_CON0); +} +EXPORT_SYMBOL(ifxmips_led_blink_clear); + +void +ifxmips_led_setup_gpio (void) +{ + int i = 0; + + /* we need to setup pins SH,D,ST (4,5,6) */ + for (i = 4; i < 7; i++) + { + ifxmips_port_set_altsel0(IFXMIPS_LED_GPIO_PORT, i); + ifxmips_port_clear_altsel1(IFXMIPS_LED_GPIO_PORT, i); + ifxmips_port_set_dir_out(IFXMIPS_LED_GPIO_PORT, i); + ifxmips_port_set_open_drain(IFXMIPS_LED_GPIO_PORT, i); + } +} + +static int +led_ioctl (struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg) +{ + int ret = -EINVAL; + + switch ( cmd ) + { + } + + return ret; +} + +static int +led_open (struct inode *inode, struct file *file) +{ + return 0; +} + +static int +led_release (struct inode *inode, struct file *file) +{ + return 0; +} + +static struct file_operations ifxmips_led_fops = { + .owner = THIS_MODULE, + .ioctl = led_ioctl, + .open = led_open, + .release = led_release +}; + + +/* +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 +*/ + + +int __init +ifxmips_led_init (void) +{ + int ret = 0; + + ifxmips_led_setup_gpio(); + + writel(0, IFXMIPS_LED_AR); + writel(0, IFXMIPS_LED_CPU0); + writel(0, IFXMIPS_LED_CPU1); + writel(LED_CON0_SWU, IFXMIPS_LED_CON0); + writel(0, IFXMIPS_LED_CON1); + + /* setup the clock edge that the shift register is triggered on */ + writel(readl(IFXMIPS_LED_CON0) & ~IFXMIPS_LED_EDGE_MASK, IFXMIPS_LED_CON0); + writel(readl(IFXMIPS_LED_CON0) | IFXMIPS_LED_CLK_EDGE, IFXMIPS_LED_CON0); + + /* per default leds 15-0 are set */ + writel(IFXMIPS_LED_GROUP1 | IFXMIPS_LED_GROUP0, IFXMIPS_LED_CON1); + + /* leds are update periodically by the FPID */ + writel(readl(IFXMIPS_LED_CON1) & ~IFXMIPS_LED_UPD_MASK, IFXMIPS_LED_CON1); + writel(readl(IFXMIPS_LED_CON1) | IFXMIPS_LED_UPD_SRC_FPI, IFXMIPS_LED_CON1); + + /* set led update speed */ + writel(readl(IFXMIPS_LED_CON1) & ~IFXMIPS_LED_MASK, IFXMIPS_LED_CON1); + writel(readl(IFXMIPS_LED_CON1) | IFXMIPS_LED_SPEED, IFXMIPS_LED_CON1); + + /* adsl 0 and 1 leds are updated by the arc */ + writel(readl(IFXMIPS_LED_CON0) | IFXMIPS_LED_ADSL_SRC, IFXMIPS_LED_CON0); + + /* per default, the leds are turned on */ + ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_LED); + + ifxmips_led_major = register_chrdev(0, "ifxmips_led", &ifxmips_led_fops); + + if (!ifxmips_led_major) + { + printk("ifxmips_led: Error! Could not register device. %d\n", ifxmips_led_major); + ret = -EINVAL; + + goto out; + } + + printk(KERN_INFO "ifxmips_led : device registered on major %d\n", ifxmips_led_major); + +out: + return ret; +} + +void __exit +ifxmips_led_exit (void) +{ + unregister_chrdev(ifxmips_led_major, "ifxmips_led"); +} + +module_init(ifxmips_led_init); +module_exit(ifxmips_led_exit); diff --git a/target/linux/ifxmips/files/drivers/char/ifxmips_ssc.c b/target/linux/ifxmips/files/drivers/char/ifxmips_ssc.c new file mode 100644 index 0000000000..495f2582fa --- /dev/null +++ b/target/linux/ifxmips/files/drivers/char/ifxmips_ssc.c @@ -0,0 +1,1533 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2006 infineon + * Copyright (C) 2007 John Crispin + * + */ + +// ### TO DO: general issues: +// - power management +// - interrupt handling (direct/indirect) +// - pin/mux-handling (just overall concept due to project dependency) +// - multiple instances capability +// - slave functionality + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#ifdef SSC_FRAME_INT_ENABLE +#undef SSC_FRAME_INT_ENABLE +#endif + +#define not_yet + +#define SPI_VINETIC + + + +/* allow the user to set the major device number */ +static int maj = 0; + +/* + * This is the per-channel data structure containing pointers, flags + * and variables for the port. This driver supports a maximum of PORT_CNT. + * isp is allocated in ifx_ssc_init() based on the chip version. + */ +static struct ifx_ssc_port *isp; + +/* prototypes for fops */ +static ssize_t ifx_ssc_read (struct file *, char *, size_t, loff_t *); +static ssize_t ifx_ssc_write (struct file *, const char *, size_t, loff_t *); +//static unsigned int ifx_ssc_poll(struct file *, struct poll_table_struct *); +int ifx_ssc_ioctl (struct inode *, struct file *, unsigned int, + unsigned long); +int ifx_ssc_open (struct inode *, struct file *); +int ifx_ssc_close (struct inode *, struct file *); + +/* other forward declarations */ +static unsigned int ifx_ssc_get_kernel_clk (struct ifx_ssc_port *info); +static void tx_int (struct ifx_ssc_port *); +static int ifx_ssc1_read_proc (char *, char **, off_t, int, int *, void *); + +extern unsigned int ifxmips_get_fpi_hz (void); +extern void mask_and_ack_ifxmips_irq (unsigned int irq_nr); + +static struct file_operations ifx_ssc_fops = { + .owner = THIS_MODULE, + .read = ifx_ssc_read, + .write = ifx_ssc_write, + .ioctl = ifx_ssc_ioctl, + .open = ifx_ssc_open, + .release = ifx_ssc_close, +}; + +static inline unsigned int +ifx_ssc_get_kernel_clk (struct ifx_ssc_port *info) +{ + unsigned int rmc; + + rmc = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_CLC) & IFX_CLC_RUN_DIVIDER_MASK) >> IFX_CLC_RUN_DIVIDER_OFFSET; + if (rmc == 0) + { + printk ("ifx_ssc_get_kernel_clk rmc==0 \n"); + return 0; + } + return ifxmips_get_fpi_hz () / rmc; +} + +#ifndef not_yet +#ifdef IFX_SSC_INT_USE_BH +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver + * (also known as the "bottom half"). This can be called any + * number of times for any channel without harm. + */ +static inline void +ifx_ssc_sched_event (struct ifx_ssc_port *info, int event) +{ + info->event |= 1 << event; /* remember what kind of event and who */ + queue_task (&info->tqueue, &tq_cyclades); /* it belongs to */ + mark_bh (CYCLADES_BH); /* then trigger event */ +} + +static void +do_softint (void *private_) +{ + struct ifx_ssc_port *info = (struct ifx_ssc_port *) private_; + + if (test_and_clear_bit (Cy_EVENT_HANGUP, &info->event)) + { + wake_up_interruptible (&info->open_wait); + info->flags &= ~(ASYNC_NORMAL_ACTIVE | ASYNC_CALLOUT_ACTIVE); + } + + if (test_and_clear_bit (Cy_EVENT_OPEN_WAKEUP, &info->event)) + wake_up_interruptible (&info->open_wait); + + if (test_and_clear_bit (Cy_EVENT_DELTA_WAKEUP, &info->event)) + wake_up_interruptible (&info->delta_msr_wait); + + if (test_and_clear_bit (Cy_EVENT_WRITE_WAKEUP, &info->event)) + wake_up_interruptible (&tty->write_wait); +#ifdef Z_WAKE + if (test_and_clear_bit (Cy_EVENT_SHUTDOWN_WAKEUP, &info->event)) + wake_up_interruptible (&info->shutdown_wait); +#endif +} +#endif +#endif + +inline static void +rx_int (struct ifx_ssc_port *info) +{ + int fifo_fill_lev, bytes_in_buf, i; + unsigned long tmp_val; + unsigned long *tmp_ptr; + unsigned int rx_valid_cnt; + /* number of words waiting in the RX FIFO */ + fifo_fill_lev = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_FSTAT) & IFX_SSC_FSTAT_RECEIVED_WORDS_MASK) >> IFX_SSC_FSTAT_RECEIVED_WORDS_OFFSET; + // Note: There are always 32 bits in a fifo-entry except for the last + // word of a contigous transfer block and except for not in rx-only + // mode and CON.ENBV set. But for this case it should be a convention + // in software which helps: + // In tx or rx/tx mode all transfers from the buffer to the FIFO are + // 32-bit wide, except for the last three bytes, which could be a + // combination of 16- and 8-bit access. + // => The whole block is received as 32-bit words as a contigous stream, + // even if there was a gap in tx which has the fifo run out of data! + // Just the last fifo entry *may* be partially filled (0, 1, 2 or 3 bytes)! + + /* free space in the RX buffer */ + bytes_in_buf = info->rxbuf_end - info->rxbuf_ptr; + // transfer with 32 bits per entry + while ((bytes_in_buf >= 4) && (fifo_fill_lev > 0)) { + tmp_ptr = (unsigned long *) info->rxbuf_ptr; + *tmp_ptr = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RB); + info->rxbuf_ptr += 4; + info->stats.rxBytes += 4; + fifo_fill_lev--; + bytes_in_buf -= 4; + } + + // now do the rest as mentioned in STATE.RXBV + while ((bytes_in_buf > 0) && (fifo_fill_lev > 0)) { + rx_valid_cnt = (READ_PERIPHERAL_REGISTER(info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_RX_BYTE_VALID_MASK) >> IFX_SSC_STATE_RX_BYTE_VALID_OFFSET; + if (rx_valid_cnt == 0) + break; + + if (rx_valid_cnt > bytes_in_buf) + rx_valid_cnt = bytes_in_buf; + + tmp_val = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RB); + + for (i = 0; i < rx_valid_cnt; i++) + { + *info->rxbuf_ptr = (tmp_val >> (8 * (rx_valid_cnt - i - 1))) & 0xff; + bytes_in_buf--; + info->rxbuf_ptr++; + } + info->stats.rxBytes += rx_valid_cnt; + } + + // check if transfer is complete + if (info->rxbuf_ptr >= info->rxbuf_end) + { + disable_irq(info->rxirq); + wake_up_interruptible (&info->rwait); + } else if ((info->opts.modeRxTx == IFX_SSC_MODE_RX) && (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RXCNT) == 0)) + { + if (info->rxbuf_end - info->rxbuf_ptr < IFX_SSC_RXREQ_BLOCK_SIZE) + WRITE_PERIPHERAL_REGISTER ((info->rxbuf_end - info->rxbuf_ptr) << IFX_SSC_RXREQ_RXCOUNT_OFFSET, info->mapbase + IFX_SSC_RXREQ); + else + WRITE_PERIPHERAL_REGISTER (IFX_SSC_RXREQ_BLOCK_SIZE << IFX_SSC_RXREQ_RXCOUNT_OFFSET, info->mapbase + IFX_SSC_RXREQ); + } +} + +inline static void +tx_int (struct ifx_ssc_port *info) +{ + + int fifo_space, fill, i; + fifo_space = ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_ID) & IFX_SSC_PERID_TXFS_MASK) >> IFX_SSC_PERID_TXFS_OFFSET) + - ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_FSTAT) & IFX_SSC_FSTAT_TRANSMIT_WORDS_MASK) >> IFX_SSC_FSTAT_TRANSMIT_WORDS_OFFSET); + + if (fifo_space == 0) + return; + + fill = info->txbuf_end - info->txbuf_ptr; + + if (fill > fifo_space * 4) + fill = fifo_space * 4; + + for (i = 0; i < fill / 4; i++) + { + // at first 32 bit access + WRITE_PERIPHERAL_REGISTER (*(UINT32 *) info->txbuf_ptr, info->mapbase + IFX_SSC_TB); + info->txbuf_ptr += 4; + } + + fifo_space -= fill / 4; + info->stats.txBytes += fill & ~0x3; + fill &= 0x3; + if ((fifo_space > 0) & (fill > 1)) + { + // trailing 16 bit access + WRITE_PERIPHERAL_REGISTER_16 (*(UINT16 *) info->txbuf_ptr, info->mapbase + IFX_SSC_TB); + info->txbuf_ptr += 2; + info->stats.txBytes += 2; + fifo_space--; + fill -= 2; + } + + if ((fifo_space > 0) & (fill > 0)) + { + // trailing 8 bit access + WRITE_PERIPHERAL_REGISTER_8 (*(UINT8 *) info->txbuf_ptr, info->mapbase + IFX_SSC_TB); + info->txbuf_ptr++; + info->stats.txBytes++; + } + + // check if transmission complete + if (info->txbuf_ptr >= info->txbuf_end) + { + disable_irq(info->txirq); + kfree (info->txbuf); + info->txbuf = NULL; + } + +} + +irqreturn_t +ifx_ssc_rx_int (int irq, void *dev_id) +{ + struct ifx_ssc_port *info = (struct ifx_ssc_port *) dev_id; + rx_int (info); + + return IRQ_HANDLED; +} + +irqreturn_t +ifx_ssc_tx_int (int irq, void *dev_id) +{ + struct ifx_ssc_port *info = (struct ifx_ssc_port *) dev_id; + tx_int (info); + + return IRQ_HANDLED; +} + +irqreturn_t +ifx_ssc_err_int (int irq, void *dev_id) +{ + struct ifx_ssc_port *info = (struct ifx_ssc_port *) dev_id; + unsigned int state; + unsigned int write_back = 0; + unsigned long flags; + + local_irq_save (flags); + state = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE); + + if ((state & IFX_SSC_STATE_RX_UFL) != 0) { + info->stats.rxUnErr++; + write_back |= IFX_SSC_WHBSTATE_CLR_RX_UFL_ERROR; + } + + if ((state & IFX_SSC_STATE_RX_OFL) != 0) { + info->stats.rxOvErr++; + write_back |= IFX_SSC_WHBSTATE_CLR_RX_OFL_ERROR; + } + + if ((state & IFX_SSC_STATE_TX_OFL) != 0) { + info->stats.txOvErr++; + write_back |= IFX_SSC_WHBSTATE_CLR_TX_OFL_ERROR; + } + + if ((state & IFX_SSC_STATE_TX_UFL) != 0) { + info->stats.txUnErr++; + write_back |= IFX_SSC_WHBSTATE_CLR_TX_UFL_ERROR; + } + + if ((state & IFX_SSC_STATE_MODE_ERR) != 0) { + info->stats.modeErr++; + write_back |= IFX_SSC_WHBSTATE_CLR_MODE_ERROR; + } + + if (write_back) + WRITE_PERIPHERAL_REGISTER (write_back, info->mapbase + IFX_SSC_WHBSTATE); + + local_irq_restore (flags); + + return IRQ_HANDLED; +} + +static void +ifx_ssc_abort (struct ifx_ssc_port *info) +{ + unsigned long flags; + bool enabled; + + local_irq_save (flags); + + disable_irq(info->rxirq); + disable_irq(info->txirq); + disable_irq(info->errirq); + + local_irq_restore (flags); + + // disable SSC (also aborts a receive request!) + // ### TO DO: Perhaps it's better to abort after the receiption of a + // complete word. The disable cuts the transmission immediatly and + // releases the chip selects. This could result in unpredictable + // behavior of connected external devices! + enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_ENABLED) != 0; + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); + + // flush fifos + WRITE_PERIPHERAL_REGISTER (IFX_SSC_XFCON_FIFO_FLUSH, info->mapbase + IFX_SSC_TXFCON); + WRITE_PERIPHERAL_REGISTER (IFX_SSC_XFCON_FIFO_FLUSH, info->mapbase + IFX_SSC_RXFCON); + + // free txbuf + if (info->txbuf != NULL) + { + kfree (info->txbuf); + info->txbuf = NULL; + } + + // wakeup read process + if (info->rxbuf != NULL) + wake_up_interruptible (&info->rwait); + + // clear pending int's + mask_and_ack_ifxmips_irq(info->rxirq); + mask_and_ack_ifxmips_irq(info->txirq); + mask_and_ack_ifxmips_irq(info->errirq); + + // clear error flags + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ALL_ERROR, info->mapbase + IFX_SSC_WHBSTATE); + + if (enabled) + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); + +} + +/* + * This routine is called whenever a port is opened. It enforces + * exclusive opening of a port and enables interrupts, etc. + */ +int +ifx_ssc_open (struct inode *inode, struct file *filp) +{ + struct ifx_ssc_port *info; + int line; + int from_kernel = 0; + + if ((inode == (struct inode *) 0) || (inode == (struct inode *) 1)) { + from_kernel = 1; + line = (int) inode; + } else { + line = MINOR (filp->f_dentry->d_inode->i_rdev); + filp->f_op = &ifx_ssc_fops; + } + + /* don't open more minor devices than we can support */ + if (line < 0 || line >= PORT_CNT) + return -ENXIO; + + info = &isp[line]; + + /* exclusive open */ + if (info->port_is_open != 0) + return -EBUSY; + info->port_is_open++; + + disable_irq(info->rxirq); + disable_irq(info->txirq); + disable_irq(info->errirq); + + /* Flush and enable TX/RX FIFO */ + WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_TXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_FLUSH | IFX_SSC_XFCON_FIFO_ENABLE, info->mapbase + IFX_SSC_TXFCON); + WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_RXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_FLUSH | IFX_SSC_XFCON_FIFO_ENABLE, info->mapbase + IFX_SSC_RXFCON); + + /* logically flush the software FIFOs */ + info->rxbuf_ptr = 0; + info->txbuf_ptr = 0; + + /* clear all error bits */ + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ALL_ERROR, info->mapbase + IFX_SSC_WHBSTATE); + + // clear pending interrupts + mask_and_ack_ifxmips_irq(info->rxirq); + mask_and_ack_ifxmips_irq(info->txirq); + mask_and_ack_ifxmips_irq(info->errirq); + + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); + + return 0; +} +EXPORT_SYMBOL(ifx_ssc_open); + +int +ifx_ssc_close (struct inode *inode, struct file *filp) +{ + struct ifx_ssc_port *info; + int idx; + + if ((inode == (struct inode *) 0) || (inode == (struct inode *) 1)) + idx = (int) inode; + else + idx = MINOR (filp->f_dentry->d_inode->i_rdev); + + if (idx < 0 || idx >= PORT_CNT) + return -ENXIO; + + info = &isp[idx]; + if (!info) + return -ENXIO; + + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); + + ifx_ssc_abort(info); + + info->port_is_open--; + + return 0; +} +EXPORT_SYMBOL(ifx_ssc_close); + +static ssize_t +ifx_ssc_read_helper_poll (struct ifx_ssc_port *info, char *buf, size_t len, int from_kernel) +{ + ssize_t ret_val; + unsigned long flags; + + if (info->opts.modeRxTx == IFX_SSC_MODE_TX) + return -EFAULT; + local_irq_save (flags); + info->rxbuf_ptr = info->rxbuf; + info->rxbuf_end = info->rxbuf + len; + local_irq_restore (flags); + /* Vinetic driver always works in IFX_SSC_MODE_RXTX */ + /* TXRX in poll mode */ + while (info->rxbuf_ptr < info->rxbuf_end) + { + if (info->txbuf_ptr < info->txbuf_end) + tx_int (info); + + rx_int (info); + }; + + ret_val = info->rxbuf_ptr - info->rxbuf; + + return ret_val; +} + +static ssize_t +ifx_ssc_read_helper (struct ifx_ssc_port *info, char *buf, size_t len, int from_kernel) +{ + ssize_t ret_val; + unsigned long flags; + DECLARE_WAITQUEUE (wait, current); + + if (info->opts.modeRxTx == IFX_SSC_MODE_TX) + return -EFAULT; + + local_irq_save (flags); + info->rxbuf_ptr = info->rxbuf; + info->rxbuf_end = info->rxbuf + len; + + if (info->opts.modeRxTx == IFX_SSC_MODE_RXTX) + { + if ((info->txbuf == NULL) || (info->txbuf != info->txbuf_ptr) || (info->txbuf_end != len + info->txbuf)) + { + local_irq_restore (flags); + printk ("IFX SSC - %s: write must be called before calling " "read in combined RX/TX!\n", __func__); + return -EFAULT; + } + + local_irq_restore(flags); + tx_int (info); + + if (info->txbuf_ptr < info->txbuf_end) + enable_irq(info->txirq); + + enable_irq(info->rxirq); + } else { + local_irq_restore(flags); + if (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RXCNT) & IFX_SSC_RXCNT_TODO_MASK) + return -EBUSY; + enable_irq(info->rxirq); + if (len < IFX_SSC_RXREQ_BLOCK_SIZE) + WRITE_PERIPHERAL_REGISTER (len << IFX_SSC_RXREQ_RXCOUNT_OFFSET, info->mapbase + IFX_SSC_RXREQ); + else + WRITE_PERIPHERAL_REGISTER (IFX_SSC_RXREQ_BLOCK_SIZE << IFX_SSC_RXREQ_RXCOUNT_OFFSET, info->mapbase + IFX_SSC_RXREQ); + } + + __add_wait_queue (&info->rwait, &wait); + set_current_state (TASK_INTERRUPTIBLE); + + do { + local_irq_save (flags); + if (info->rxbuf_ptr >= info->rxbuf_end) + break; + + local_irq_restore (flags); + + if (signal_pending (current)) + { + ret_val = -ERESTARTSYS; + goto out; + } + schedule(); + } while (1); + + ret_val = info->rxbuf_ptr - info->rxbuf; + local_irq_restore (flags); + +out: + current->state = TASK_RUNNING; + __remove_wait_queue (&info->rwait, &wait); + + return (ret_val); +} + +static ssize_t +ifx_ssc_write_helper (struct ifx_ssc_port *info, const char *buf, + size_t len, int from_kernel) +{ + if (info->opts.modeRxTx == IFX_SSC_MODE_RX) + return -EFAULT; + + info->txbuf_ptr = info->txbuf; + info->txbuf_end = len + info->txbuf; + if (info->opts.modeRxTx == IFX_SSC_MODE_TX) + { + tx_int (info); + if (info->txbuf_ptr < info->txbuf_end) + { + enable_irq(info->txirq); + } + } + + return len; +} + +ssize_t +ifx_ssc_kread (int port, char *kbuf, size_t len) +{ + struct ifx_ssc_port *info; + ssize_t ret_val; + + if (port < 0 || port >= PORT_CNT) + return -ENXIO; + + if (len == 0) + return 0; + + info = &isp[port]; + + if (info->rxbuf != NULL) + { + printk ("SSC device busy\n"); + return -EBUSY; + } + + info->rxbuf = kbuf; + if (info->rxbuf == NULL) + { + printk ("SSC device error\n"); + return -EINVAL; + } + + ret_val = ifx_ssc_read_helper_poll (info, kbuf, len, 1); + info->rxbuf = NULL; + + disable_irq(info->rxirq); + + return ret_val; +} +EXPORT_SYMBOL(ifx_ssc_kread); + +ssize_t +ifx_ssc_kwrite (int port, const char *kbuf, size_t len) +{ + struct ifx_ssc_port *info; + ssize_t ret_val; + + if (port < 0 || port >= PORT_CNT) + return -ENXIO; + + if (len == 0) + return 0; + + info = &isp[port]; + + // check if transmission in progress + if (info->txbuf != NULL) + return -EBUSY; + + info->txbuf = (char *) kbuf; + + ret_val = ifx_ssc_write_helper (info, info->txbuf, len, 1); + + if (ret_val < 0) + info->txbuf = NULL; + + return ret_val; +} +EXPORT_SYMBOL(ifx_ssc_kwrite); + +static ssize_t +ifx_ssc_read (struct file *filp, char *ubuf, size_t len, loff_t * off) +{ + ssize_t ret_val; + int idx; + struct ifx_ssc_port *info; + + idx = MINOR (filp->f_dentry->d_inode->i_rdev); + info = &isp[idx]; + + if (info->rxbuf != NULL) + return -EBUSY; + + info->rxbuf = kmalloc (len + 3, GFP_KERNEL); + if (info->rxbuf == NULL) + return -ENOMEM; + + ret_val = ifx_ssc_read_helper (info, info->rxbuf, len, 0); + if (copy_to_user ((void *) ubuf, info->rxbuf, ret_val) != 0) + ret_val = -EFAULT; + + disable_irq(info->rxirq); + + kfree (info->rxbuf); + info->rxbuf = NULL; + + return (ret_val); +} + +static ssize_t +ifx_ssc_write (struct file *filp, const char *ubuf, size_t len, loff_t * off) +{ + int idx; + struct ifx_ssc_port *info; + int ret_val; + + if (len == 0) + return (0); + + idx = MINOR (filp->f_dentry->d_inode->i_rdev); + info = &isp[idx]; + + if (info->txbuf != NULL) + return -EBUSY; + + info->txbuf = kmalloc (len + 3, GFP_KERNEL); + if (info->txbuf == NULL) + return -ENOMEM; + + ret_val = copy_from_user (info->txbuf, ubuf, len); + if (ret_val == 0) + ret_val = ifx_ssc_write_helper (info, info->txbuf, len, 0); + else + ret_val = -EFAULT; + + if (ret_val < 0) + { + kfree (info->txbuf); + info->txbuf = NULL; + } + + return (ret_val); +} + +static struct ifx_ssc_frm_status * +ifx_ssc_frm_status_get (struct ifx_ssc_port *info) +{ + unsigned long tmp; + + tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFSTAT); + info->frm_status.DataBusy = (tmp & IFX_SSC_SFSTAT_IN_DATA) > 0; + info->frm_status.PauseBusy = (tmp & IFX_SSC_SFSTAT_IN_PAUSE) > 0; + info->frm_status.DataCount = (tmp & IFX_SSC_SFSTAT_DATA_COUNT_MASK) >> IFX_SSC_SFSTAT_DATA_COUNT_OFFSET; + info->frm_status.PauseCount = (tmp & IFX_SSC_SFSTAT_PAUSE_COUNT_MASK) >> IFX_SSC_SFSTAT_PAUSE_COUNT_OFFSET; + tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFCON); + info->frm_status.EnIntAfterData = (tmp & IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE) > 0; + info->frm_status.EnIntAfterPause = (tmp & IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE) > 0; + + return &info->frm_status; +} + + +static struct ifx_ssc_frm_opts * +ifx_ssc_frm_control_get (struct ifx_ssc_port *info) +{ + unsigned long tmp; + + tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFCON); + info->frm_opts.FrameEnable = (tmp & IFX_SSC_SFCON_SF_ENABLE) > 0; + info->frm_opts.DataLength = (tmp & IFX_SSC_SFCON_DATA_LENGTH_MASK) >> IFX_SSC_SFCON_DATA_LENGTH_OFFSET; + info->frm_opts.PauseLength = (tmp & IFX_SSC_SFCON_PAUSE_LENGTH_MASK) >> IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET; + info->frm_opts.IdleData = (tmp & IFX_SSC_SFCON_PAUSE_DATA_MASK) >> IFX_SSC_SFCON_PAUSE_DATA_OFFSET; + info->frm_opts.IdleClock = (tmp & IFX_SSC_SFCON_PAUSE_CLOCK_MASK) >> IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET; + info->frm_opts.StopAfterPause = (tmp & IFX_SSC_SFCON_STOP_AFTER_PAUSE) > 0; + + return &info->frm_opts; +} + +static int +ifx_ssc_frm_control_set (struct ifx_ssc_port *info) +{ + unsigned long tmp; + + // check parameters + if ((info->frm_opts.DataLength > IFX_SSC_SFCON_DATA_LENGTH_MAX) + || (info->frm_opts.DataLength < 1) + || (info->frm_opts.PauseLength > IFX_SSC_SFCON_PAUSE_LENGTH_MAX) + || (info->frm_opts.PauseLength < 1) + || (info->frm_opts.IdleData & ~(IFX_SSC_SFCON_PAUSE_DATA_MASK >> IFX_SSC_SFCON_PAUSE_DATA_OFFSET)) + || (info->frm_opts.IdleClock & ~(IFX_SSC_SFCON_PAUSE_CLOCK_MASK >> IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET))) + return -EINVAL; + + // read interrupt bits (they're not changed here) + tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_SFCON) & + (IFX_SSC_SFCON_FIR_ENABLE_BEFORE_PAUSE | IFX_SSC_SFCON_FIR_ENABLE_AFTER_PAUSE); + + // set all values with respect to it's bit position (for data and pause + // length set N-1) + tmp = (info->frm_opts.DataLength - 1) << IFX_SSC_SFCON_DATA_LENGTH_OFFSET; + tmp |= (info->frm_opts.PauseLength - 1) << IFX_SSC_SFCON_PAUSE_LENGTH_OFFSET; + tmp |= info->frm_opts.IdleData << IFX_SSC_SFCON_PAUSE_DATA_OFFSET; + tmp |= info->frm_opts.IdleClock << IFX_SSC_SFCON_PAUSE_CLOCK_OFFSET; + tmp |= info->frm_opts.FrameEnable * IFX_SSC_SFCON_SF_ENABLE; + tmp |= info->frm_opts.StopAfterPause * IFX_SSC_SFCON_STOP_AFTER_PAUSE; + + WRITE_PERIPHERAL_REGISTER(tmp, info->mapbase + IFX_SSC_SFCON); + + return 0; +} + +static int +ifx_ssc_rxtx_mode_set (struct ifx_ssc_port *info, unsigned int val) +{ + unsigned long tmp; + + if (!(info) || (val & ~(IFX_SSC_MODE_MASK))) + return -EINVAL; + + if ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_BUSY) + || (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_RXCNT) & IFX_SSC_RXCNT_TODO_MASK)) + return -EBUSY; + + tmp = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_CON) & ~(IFX_SSC_CON_RX_OFF | IFX_SSC_CON_TX_OFF)) | (val); + WRITE_PERIPHERAL_REGISTER (tmp, info->mapbase + IFX_SSC_CON); + info->opts.modeRxTx = val; + + return 0; +} + +static int +ifx_ssc_sethwopts (struct ifx_ssc_port *info) +{ + unsigned long flags, bits; + struct ifx_ssc_hwopts *opts = &info->opts; + + if ((opts->dataWidth < IFX_SSC_MIN_DATA_WIDTH) + || (opts->dataWidth > IFX_SSC_MAX_DATA_WIDTH)) + return -EINVAL; + + bits = (opts->dataWidth - 1) << IFX_SSC_CON_DATA_WIDTH_OFFSET; + bits |= IFX_SSC_CON_ENABLE_BYTE_VALID; + + if (opts->rxOvErrDetect) + bits |= IFX_SSC_CON_RX_OFL_CHECK; + if (opts->rxUndErrDetect) + bits |= IFX_SSC_CON_RX_UFL_CHECK; + if (opts->txOvErrDetect) + bits |= IFX_SSC_CON_TX_OFL_CHECK; + if (opts->txUndErrDetect) + bits |= IFX_SSC_CON_TX_UFL_CHECK; + if (opts->loopBack) + bits |= IFX_SSC_CON_LOOPBACK_MODE; + if (opts->echoMode) + bits |= IFX_SSC_CON_ECHO_MODE_ON; + if (opts->headingControl) + bits |= IFX_SSC_CON_MSB_FIRST; + if (opts->clockPhase) + bits |= IFX_SSC_CON_LATCH_THEN_SHIFT; + if (opts->clockPolarity) + bits |= IFX_SSC_CON_CLOCK_FALL; + + switch (opts->modeRxTx) + { + case IFX_SSC_MODE_TX: + bits |= IFX_SSC_CON_RX_OFF; + break; + case IFX_SSC_MODE_RX: + bits |= IFX_SSC_CON_TX_OFF; + break; + } + + local_irq_save (flags); + + WRITE_PERIPHERAL_REGISTER (bits, info->mapbase + IFX_SSC_CON); + WRITE_PERIPHERAL_REGISTER ((info->opts.gpoCs << IFX_SSC_GPOCON_ISCSB0_POS) | + (info->opts.gpoInv << IFX_SSC_GPOCON_INVOUT0_POS), info->mapbase + IFX_SSC_GPOCON); + + WRITE_PERIPHERAL_REGISTER (info->opts.gpoCs << IFX_SSC_WHBGPOSTAT_SETOUT0_POS, info->mapbase + IFX_SSC_WHBGPOSTAT); + + //master mode + if (opts->masterSelect) + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_MASTER_SELECT, info->mapbase + IFX_SSC_WHBSTATE); + else + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_MASTER_SELECT, info->mapbase + IFX_SSC_WHBSTATE); + + // init serial framing + WRITE_PERIPHERAL_REGISTER (0, info->mapbase + IFX_SSC_SFCON); + /* set up the port pins */ + //check for general requirements to switch (external) pad/pin characteristics + /* TODO: P0.9 SPI_CS4, P0.10 SPI_CS5, P 0.11 SPI_CS6, because of ASC0 */ + /* p0.15 SPI_CS1(EEPROM), P0.13 SPI_CS3, */ + /* Set p0.15 to alternative 01, others to 00 (In/OUT) */ + *(IFXMIPS_GPIO_P0_DIR) = (*IFXMIPS_GPIO_P0_DIR) | (0xA000); + *(IFXMIPS_GPIO_P0_ALTSEL0) = (((*IFXMIPS_GPIO_P0_ALTSEL0) | (0x8000)) & (~(0x2000))); + *(IFXMIPS_GPIO_P0_ALTSEL1) = (((*IFXMIPS_GPIO_P0_ALTSEL1) & (~0x8000)) & (~(0x2000))); + *(IFXMIPS_GPIO_P0_OD) = (*IFXMIPS_GPIO_P0_OD) | 0xA000; + + /* p1.6 SPI_CS2(SFLASH), p1.0 SPI_DIN, p1.1 SPI_DOUT, p1.2 SPI_CLK */ + *(IFXMIPS_GPIO_P1_DIR) = ((*IFXMIPS_GPIO_P1_DIR) | (0x46)) & (~1); + *(IFXMIPS_GPIO_P1_ALTSEL0) = ((*IFXMIPS_GPIO_P1_ALTSEL0) | (0x47)); + *(IFXMIPS_GPIO_P1_ALTSEL1) = (*IFXMIPS_GPIO_P1_ALTSEL1) & (~0x47); + *(IFXMIPS_GPIO_P1_OD) = (*IFXMIPS_GPIO_P1_OD) | 0x0046; + + /*CS3 */ + /*TODO: CS4 CS5 CS6 */ + *IFXMIPS_GPIO_P0_OUT = ((*IFXMIPS_GPIO_P0_OUT) | 0x2000); + + local_irq_restore (flags); + + return 0; +} + +static int +ifx_ssc_set_baud (struct ifx_ssc_port *info, unsigned int baud) +{ + unsigned int ifx_ssc_clock; + unsigned int br; + unsigned long flags; + bool enabled; + int retval = 0; + + ifx_ssc_clock = ifx_ssc_get_kernel_clk(info); + if (ifx_ssc_clock == 0) + { + retval = -EINVAL; + goto out; + } + + local_irq_save (flags); + + enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_ENABLED); + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); + + br = (((ifx_ssc_clock >> 1) + baud / 2) / baud) - 1; + wmb(); + + if (br > 0xffff || ((br == 0) && + ((READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_MASTER) == 0))) { + local_irq_restore (flags); + printk ("%s: invalid baudrate %u\n", __func__, baud); + return -EINVAL; + } + + WRITE_PERIPHERAL_REGISTER (br, info->mapbase + IFX_SSC_BR); + + if (enabled) + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); + + local_irq_restore(flags); + +out: + return retval; +} + +static int +ifx_ssc_hwinit (struct ifx_ssc_port *info) +{ + unsigned long flags; + bool enabled; + + enabled = (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) & IFX_SSC_STATE_IS_ENABLED); + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); + + if (ifx_ssc_sethwopts (info) < 0) + { + printk ("%s: setting the hardware options failed\n", __func__); + return -EINVAL; + } + + if (ifx_ssc_set_baud (info, info->baud) < 0) + { + printk ("%s: setting the baud rate failed\n", __func__); + return -EINVAL; + } + + local_irq_save (flags); + + /* TX FIFO */ + WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_TXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_ENABLE, + info->mapbase + IFX_SSC_TXFCON); + /* RX FIFO */ + WRITE_PERIPHERAL_REGISTER ((IFX_SSC_DEF_RXFIFO_FL << IFX_SSC_XFCON_ITL_OFFSET) | IFX_SSC_XFCON_FIFO_ENABLE, + info->mapbase + IFX_SSC_RXFCON); + + local_irq_restore (flags); + + if (enabled) + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_SET_ENABLE, info->mapbase + IFX_SSC_WHBSTATE); + + return 0; +} + +int +ifx_ssc_ioctl (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long data) +{ + struct ifx_ssc_port *info; + int line, ret_val = 0; + unsigned long flags; + unsigned long tmp; + int from_kernel = 0; + + if ((inode == (struct inode *) 0) || (inode == (struct inode *) 1)) + { + from_kernel = 1; + line = (int) inode; + } else { + line = MINOR (filp->f_dentry->d_inode->i_rdev); + } + + if (line < 0 || line >= PORT_CNT) + return -ENXIO; + + info = &isp[line]; + + switch (cmd) + { + case IFX_SSC_STATS_READ: + /* data must be a pointer to a struct ifx_ssc_statistics */ + if (from_kernel) + memcpy ((void *) data, (void *) &info->stats, + sizeof (struct ifx_ssc_statistics)); + else if (copy_to_user ((void *) data, + (void *) &info->stats, + sizeof (struct ifx_ssc_statistics))) + ret_val = -EFAULT; + break; + case IFX_SSC_STATS_RESET: + /* just resets the statistics counters */ + memset ((void *) &info->stats, 0, + sizeof (struct ifx_ssc_statistics)); + break; + case IFX_SSC_BAUD_SET: + /* if the buffers are not empty then the port is */ + /* busy and we shouldn't change things on-the-fly! */ + if (!info->txbuf || !info->rxbuf || + (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) + & IFX_SSC_STATE_BUSY)) { + ret_val = -EBUSY; + break; + } + /* misuse flags */ + if (from_kernel) + flags = *((unsigned long *) data); + else if (copy_from_user ((void *) &flags, + (void *) data, sizeof (flags))) { + ret_val = -EFAULT; + break; + } + if (flags == 0) { + ret_val = -EINVAL; + break; + } + if (ifx_ssc_set_baud (info, flags) < 0) { + ret_val = -EINVAL; + break; + } + info->baud = flags; + break; + case IFX_SSC_BAUD_GET: + if (from_kernel) + *((unsigned int *) data) = info->baud; + else if (copy_to_user ((void *) data, + (void *) &info->baud, + sizeof (unsigned long))) + ret_val = -EFAULT; + break; + case IFX_SSC_RXTX_MODE_SET: + if (from_kernel) + tmp = *((unsigned long *) data); + else if (copy_from_user ((void *) &tmp, + (void *) data, sizeof (tmp))) { + ret_val = -EFAULT; + break; + } + ret_val = ifx_ssc_rxtx_mode_set (info, tmp); + break; + case IFX_SSC_RXTX_MODE_GET: + tmp = READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_CON) & + (~(IFX_SSC_CON_RX_OFF | IFX_SSC_CON_TX_OFF)); + if (from_kernel) + *((unsigned int *) data) = tmp; + else if (copy_to_user ((void *) data, + (void *) &tmp, sizeof (tmp))) + ret_val = -EFAULT; + break; + + case IFX_SSC_ABORT: + ifx_ssc_abort (info); + break; + + case IFX_SSC_GPO_OUT_SET: + if (from_kernel) + tmp = *((unsigned long *) data); + else if (copy_from_user ((void *) &tmp, + (void *) data, sizeof (tmp))) { + ret_val = -EFAULT; + break; + } + if (tmp > IFX_SSC_MAX_GPO_OUT) + ret_val = -EINVAL; + else + WRITE_PERIPHERAL_REGISTER + (1 << (tmp + IFX_SSC_WHBGPOSTAT_SETOUT0_POS), + info->mapbase + IFX_SSC_WHBGPOSTAT); + break; + case IFX_SSC_GPO_OUT_CLR: + if (from_kernel) + tmp = *((unsigned long *) data); + else if (copy_from_user ((void *) &tmp, + (void *) data, sizeof (tmp))) { + ret_val = -EFAULT; + break; + } + if (tmp > IFX_SSC_MAX_GPO_OUT) + ret_val = -EINVAL; + else { + WRITE_PERIPHERAL_REGISTER + (1 << (tmp + IFX_SSC_WHBGPOSTAT_CLROUT0_POS), + info->mapbase + IFX_SSC_WHBGPOSTAT); + } + break; + case IFX_SSC_GPO_OUT_GET: + tmp = READ_PERIPHERAL_REGISTER + (info->mapbase + IFX_SSC_GPOSTAT); + if (from_kernel) + *((unsigned int *) data) = tmp; + else if (copy_to_user ((void *) data, + (void *) &tmp, sizeof (tmp))) + ret_val = -EFAULT; + break; + case IFX_SSC_FRM_STATUS_GET: + ifx_ssc_frm_status_get (info); + if (from_kernel) + memcpy ((void *) data, (void *) &info->frm_status, + sizeof (struct ifx_ssc_frm_status)); + else if (copy_to_user ((void *) data, + (void *) &info->frm_status, + sizeof (struct ifx_ssc_frm_status))) + ret_val = -EFAULT; + break; + case IFX_SSC_FRM_CONTROL_GET: + ifx_ssc_frm_control_get (info); + if (from_kernel) + memcpy ((void *) data, (void *) &info->frm_opts, + sizeof (struct ifx_ssc_frm_opts)); + else if (copy_to_user ((void *) data, + (void *) &info->frm_opts, + sizeof (struct ifx_ssc_frm_opts))) + ret_val = -EFAULT; + break; + case IFX_SSC_FRM_CONTROL_SET: + if (from_kernel) + memcpy ((void *) &info->frm_opts, (void *) data, + sizeof (struct ifx_ssc_frm_opts)); + else if (copy_to_user ((void *) &info->frm_opts, + (void *) data, + sizeof (struct ifx_ssc_frm_opts))) { + ret_val = -EFAULT; + break; + } + ret_val = ifx_ssc_frm_control_set (info); + break; + case IFX_SSC_HWOPTS_SET: + /* data must be a pointer to a struct ifx_ssc_hwopts */ + /* if the buffers are not empty then the port is */ + /* busy and we shouldn't change things on-the-fly! */ + if (!info->txbuf || !info->rxbuf || + (READ_PERIPHERAL_REGISTER (info->mapbase + IFX_SSC_STATE) + & IFX_SSC_STATE_BUSY)) { + ret_val = -EBUSY; + break; + } + if (from_kernel) + memcpy ((void *) &info->opts, (void *) data, + sizeof (struct ifx_ssc_hwopts)); + else if (copy_from_user ((void *) &info->opts, + (void *) data, + sizeof (struct ifx_ssc_hwopts))) { + ret_val = -EFAULT; + break; + } + if (ifx_ssc_hwinit (info) < 0) { + ret_val = -EIO; + } + break; + case IFX_SSC_HWOPTS_GET: + /* data must be a pointer to a struct ifx_ssc_hwopts */ + if (from_kernel) + memcpy ((void *) data, (void *) &info->opts, + sizeof (struct ifx_ssc_hwopts)); + else if (copy_to_user ((void *) data, + (void *) &info->opts, + sizeof (struct ifx_ssc_hwopts))) + ret_val = -EFAULT; + break; + default: + ret_val = -ENOIOCTLCMD; + } + + return ret_val; +} +EXPORT_SYMBOL(ifx_ssc_ioctl); + +static int +ifx_ssc1_read_proc (char *page, char **start, off_t offset, int count, int *eof, void *data) +{ + int off = 0; + unsigned long flags; + + local_save_flags(flags); + local_irq_disable(); + + off += sprintf (page + off, "Statistics for Infineon Synchronous Serial Controller SSC1\n"); + off += sprintf (page + off, "RX overflow errors %d\n", isp[0].stats.rxOvErr); + off += sprintf (page + off, "RX underflow errors %d\n", isp[0].stats.rxUnErr); + off += sprintf (page + off, "TX overflow errors %d\n", isp[0].stats.txOvErr); + off += sprintf (page + off, "TX underflow errors %d\n", isp[0].stats.txUnErr); + off += sprintf (page + off, "Abort errors %d\n", isp[0].stats.abortErr); + off += sprintf (page + off, "Mode errors %d\n", isp[0].stats.modeErr); + off += sprintf (page + off, "RX Bytes %d\n", isp[0].stats.rxBytes); + off += sprintf (page + off, "TX Bytes %d\n", isp[0].stats.txBytes); + + local_irq_restore(flags); + *eof = 1; + + return off; +} + +int __init +ifx_ssc_init (void) +{ + struct ifx_ssc_port *info; + int i, nbytes; + unsigned long flags; + int ret_val; + + ret_val = -ENOMEM; + nbytes = PORT_CNT * sizeof(struct ifx_ssc_port); + isp = (struct ifx_ssc_port*)kmalloc(nbytes, GFP_KERNEL); + + if (isp == NULL) + { + printk("%s: no memory for isp\n", __func__); + return (ret_val); + } + memset(isp, 0, nbytes); + + ret_val = -ENXIO; + if ((i = register_chrdev (maj, "ssc", &ifx_ssc_fops)) < 0) + { + printk ("Unable to register major %d for the Infineon SSC\n", maj); + if (maj == 0) + { + goto errout; + } else { + maj = 0; + if ((i = register_chrdev (maj, "ssc", &ifx_ssc_fops)) < 0) + { + printk ("Unable to register major %d for the Infineon SSC\n", maj); + goto errout; + } + } + } + + if (maj == 0) + maj = i; + + /* set default values in ifx_ssc_port */ + for (i = 0; i < PORT_CNT; i++) { + info = &isp[i]; + info->port_nr = i; + /* default values for the HwOpts */ + info->opts.AbortErrDetect = IFX_SSC_DEF_ABRT_ERR_DETECT; + info->opts.rxOvErrDetect = IFX_SSC_DEF_RO_ERR_DETECT; + info->opts.rxUndErrDetect = IFX_SSC_DEF_RU_ERR_DETECT; + info->opts.txOvErrDetect = IFX_SSC_DEF_TO_ERR_DETECT; + info->opts.txUndErrDetect = IFX_SSC_DEF_TU_ERR_DETECT; + info->opts.loopBack = IFX_SSC_DEF_LOOP_BACK; + info->opts.echoMode = IFX_SSC_DEF_ECHO_MODE; + info->opts.idleValue = IFX_SSC_DEF_IDLE_DATA; + info->opts.clockPolarity = IFX_SSC_DEF_CLOCK_POLARITY; + info->opts.clockPhase = IFX_SSC_DEF_CLOCK_PHASE; + info->opts.headingControl = IFX_SSC_DEF_HEADING_CONTROL; + info->opts.dataWidth = IFX_SSC_DEF_DATA_WIDTH; + info->opts.modeRxTx = IFX_SSC_DEF_MODE_RXTX; + info->opts.gpoCs = IFX_SSC_DEF_GPO_CS; + info->opts.gpoInv = IFX_SSC_DEF_GPO_INV; + info->opts.masterSelect = IFX_SSC_DEF_MASTERSLAVE; + info->baud = IFX_SSC_DEF_BAUDRATE; + info->rxbuf = NULL; + info->txbuf = NULL; + /* values specific to SSC1 */ + if (i == 0) { + info->mapbase = IFXMIPS_SSC1_BASE_ADDR; + info->txirq = IFXMIPS_SSC_TIR; + info->rxirq = IFXMIPS_SSC_RIR; + info->errirq = IFXMIPS_SSC_EIR; + } + + WRITE_PERIPHERAL_REGISTER (IFX_SSC_DEF_RMC << IFX_CLC_RUN_DIVIDER_OFFSET, info->mapbase + IFX_SSC_CLC); + + init_waitqueue_head (&info->rwait); + + local_irq_save (flags); + + // init serial framing register + WRITE_PERIPHERAL_REGISTER (IFX_SSC_DEF_SFCON, info->mapbase + IFX_SSC_SFCON); + + ret_val = request_irq(info->txirq, ifx_ssc_tx_int, SA_INTERRUPT, "ifx_ssc_tx", info); + if (ret_val) + { + printk("%s: unable to get irq %d\n", __func__, info->txirq); + local_irq_restore(flags); + goto errout; + } + + ret_val = request_irq(info->rxirq, ifx_ssc_rx_int, SA_INTERRUPT, "ifx_ssc_rx", info); + if (ret_val) + { + printk ("%s: unable to get irq %d\n", __func__, info->rxirq); + local_irq_restore (flags); + goto irqerr; + } + + ret_val = request_irq(info->errirq, ifx_ssc_err_int, SA_INTERRUPT,"ifx_ssc_err", info); + if (ret_val) + { + printk ("%s: unable to get irq %d\n", __func__, info->errirq); + local_irq_restore (flags); + goto irqerr; + } + WRITE_PERIPHERAL_REGISTER (IFX_SSC_DEF_IRNEN, info->mapbase + IFX_SSC_IRN_EN); + + enable_irq(info->txirq); + enable_irq(info->rxirq); + enable_irq(info->errirq); + + local_irq_restore (flags); + } + + for (i = 0; i < PORT_CNT; i++) { + info = &isp[i]; + if (ifx_ssc_hwinit (info) < 0) + { + printk ("%s: hardware init failed for port %d\n", __func__, i); + goto irqerr; + } + } + + create_proc_read_entry ("driver/ssc1", 0, NULL, ifx_ssc1_read_proc, NULL); + + return 0; + +irqerr: + free_irq(isp[0].txirq, &isp[0]); + free_irq(isp[0].rxirq, &isp[0]); + free_irq(isp[0].errirq, &isp[0]); +errout: + kfree (isp); + return (ret_val); +} + +void +ifx_ssc_cleanup_module (void) +{ + int i; + + for (i = 0; i < PORT_CNT; i++) { + WRITE_PERIPHERAL_REGISTER (IFX_SSC_WHBSTATE_CLR_ENABLE, isp[i].mapbase + IFX_SSC_WHBSTATE); + free_irq(isp[i].txirq, &isp[i]); + free_irq(isp[i].rxirq, &isp[i]); + free_irq(isp[i].errirq, &isp[i]); + } + kfree (isp); + remove_proc_entry ("driver/ssc1", NULL); +} + +module_init(ifx_ssc_init); +module_exit(ifx_ssc_cleanup_module); + + +inline int +ifx_ssc_cs_low (u32 pin) +{ + int ret = 0; + if ((ret = ifx_ssc_ioctl ((struct inode *) 0, NULL, IFX_SSC_GPO_OUT_CLR, (unsigned long) &pin))) + printk ("clear CS %d fails\n", pin); + wmb (); + + return ret; +} +EXPORT_SYMBOL(ifx_ssc_cs_low); + +inline int +ifx_ssc_cs_high (u32 pin) +{ + int ret = 0; + if ((ret = ifx_ssc_ioctl((struct inode *) 0, NULL, IFX_SSC_GPO_OUT_SET, (unsigned long) &pin))) + printk ("set CS %d fails\n", pin); + wmb (); + + return ret; +} +EXPORT_SYMBOL(ifx_ssc_cs_high); + +static int +ssc_session (char *tx_buf, u32 tx_len, char *rx_buf, u32 rx_len) +{ + int ret = 0; + + char *ssc_tx_buf = NULL; + char *ssc_rx_buf = NULL; + int eff_size = 0; + u8 mode = 0; + + if (tx_buf == NULL && tx_len == 0 && rx_buf == NULL && rx_len == 0) { + printk ("invalid parameters\n"); + ret = -EINVAL; + goto ssc_session_exit; + } + else if (tx_buf == NULL || tx_len == 0) { + if (rx_buf != NULL && rx_len != 0) { + mode = IFX_SSC_MODE_RX; + } + else { + printk ("invalid parameters\n"); + ret = -EINVAL; + goto ssc_session_exit; + } + } + else if (rx_buf == NULL || rx_len == 0) { + if (tx_buf != NULL && tx_len != 0) { + mode = IFX_SSC_MODE_TX; + } + else { + printk ("invalid parameters\n"); + ret = -EINVAL; + goto ssc_session_exit; + } + } + else { + mode = IFX_SSC_MODE_RXTX; + } + + if (mode == IFX_SSC_MODE_RXTX) { + eff_size = tx_len + rx_len; + } + else if (mode == IFX_SSC_MODE_RX) { + eff_size = rx_len; + } + else { + eff_size = tx_len; + } + + //4 bytes alignment, required by driver + /* change by TaiCheng */ + //if (in_irq()){ + if (1) { + ssc_tx_buf = + (char *) kmalloc (sizeof (char) * + ((eff_size + 3) & (~3)), + GFP_ATOMIC); + ssc_rx_buf = + (char *) kmalloc (sizeof (char) * + ((eff_size + 3) & (~3)), + GFP_ATOMIC); + } + else { + ssc_tx_buf = + (char *) kmalloc (sizeof (char) * + ((eff_size + 3) & (~3)), + GFP_KERNEL); + ssc_rx_buf = + (char *) kmalloc (sizeof (char) * + ((eff_size + 3) & (~3)), + GFP_KERNEL); + } + if (ssc_tx_buf == NULL || ssc_rx_buf == NULL) { + printk ("no memory for size of %d\n", eff_size); + ret = -ENOMEM; + goto ssc_session_exit; + } + memset ((void *) ssc_tx_buf, 0, eff_size); + memset ((void *) ssc_rx_buf, 0, eff_size); + + if (tx_len > 0) { + memcpy (ssc_tx_buf, tx_buf, tx_len); + } + + ret = ifx_ssc_kwrite (0, ssc_tx_buf, eff_size); + + if (ret > 0) { + ssc_tx_buf = NULL; //should be freed by ifx_ssc_kwrite + } + + if (ret != eff_size) { + printk ("ifx_ssc_write return %d\n", ret); + goto ssc_session_exit; + } + ret = ifx_ssc_kread (0, ssc_rx_buf, eff_size); + if (ret != eff_size) { + printk ("ifx_ssc_read return %d\n", ret); + goto ssc_session_exit; + } + + memcpy (rx_buf, ssc_rx_buf + tx_len, rx_len); + + if (mode == IFX_SSC_MODE_TX) { + ret = tx_len; + } + else { + ret = rx_len; + } + ssc_session_exit: + + if (ssc_tx_buf != NULL) + kfree (ssc_tx_buf); + if (ssc_rx_buf != NULL) + kfree (ssc_rx_buf); + + if (ret < 0) { + printk ("ssc session fails\n"); + } + return ret; +} + +int +ifx_ssc_txrx (char *tx_buf, u32 tx_len, char *rx_buf, u32 rx_len) +{ + return ssc_session(tx_buf, tx_len, rx_buf, rx_len); +} +EXPORT_SYMBOL(ifx_ssc_txrx); + +int +ifx_ssc_tx (char *tx_buf, u32 tx_len) +{ + return ssc_session(tx_buf, tx_len, NULL, 0); +} +EXPORT_SYMBOL(ifx_ssc_tx); + +int +ifx_ssc_rx (char *rx_buf, u32 rx_len) +{ + return ssc_session(NULL, 0, rx_buf, rx_len); +} +EXPORT_SYMBOL(ifx_ssc_rx); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("ifxmips ssc driver"); + diff --git a/target/linux/ifxmips/files/drivers/char/watchdog/danube_wdt.c b/target/linux/ifxmips/files/drivers/char/watchdog/danube_wdt.c deleted file mode 100644 index 8fcbc88030..0000000000 --- a/target/linux/ifxmips/files/drivers/char/watchdog/danube_wdt.c +++ /dev/null @@ -1,287 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) 2006 infineon - * Copyright (C) 2007 John Crispin - * - */ - -#include -#include -#include -#include -#include -#include -#include - - -// TODO remove magic numbers and weirdo macros - -extern unsigned int ifxmips_get_fpi_hz (void); - -static int ifxmips_wdt_inuse = 0; -static int ifxmips_wdt_major = 0; - -int -ifxmips_wdt_enable (unsigned int timeout) -{ - unsigned int wdt_cr = 0; - unsigned int wdt_reload = 0; - unsigned int wdt_clkdiv, wdt_pwl, ffpi; - int retval = 0; - - /* clock divider & prewarning limit */ - wdt_clkdiv = 1 << (7 * IFXMIPS_BIU_WDT_CR_CLKDIV_GET(readl(IFXMIPS_BIU_WDT_CR))); - wdt_pwl = 0x8000 >> IFXMIPS_BIU_WDT_CR_PWL_GET(readl(IFXMIPS_BIU_WDT_CR)); - - //TODO - printk("WARNING FUNCTION CALL MISSING!!!"); - //ffpi = cgu_get_io_region_clock(); - printk("cpu clock = %d\n", ffpi); - - /* caculate reload value */ - wdt_reload = (timeout * (ffpi / wdt_clkdiv)) + wdt_pwl; - - printk("wdt_pwl=0x%x, wdt_clkdiv=%d, ffpi=%d, wdt_reload = 0x%x\n", - wdt_pwl, wdt_clkdiv, ffpi, wdt_reload); - - if (wdt_reload > 0xFFFF) - { - printk ("timeout too large %d\n", timeout); - retval = -EINVAL; - goto out; - } - - /* Write first part of password access */ - writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); - - wdt_cr = readl(IFXMIPS_BIU_WDT_CR); - wdt_cr &= (!IFXMIPS_BIU_WDT_CR_PW_SET(0xff) & - !IFXMIPS_BIU_WDT_CR_PWL_SET(0x3) & - !IFXMIPS_BIU_WDT_CR_CLKDIV_SET(0x3) & - !IFXMIPS_BIU_WDT_CR_RELOAD_SET(0xffff)); - - wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | - IFXMIPS_BIU_WDT_CR_PWL_SET(IFXMIPS_BIU_WDT_CR_PWL_GET(readl(IFXMIPS_BIU_WDT_CR))) | - IFXMIPS_BIU_WDT_CR_CLKDIV_SET(IFXMIPS_BIU_WDT_CR_CLKDIV_GET(readl(IFXMIPS_BIU_WDT_CR))) | - IFXMIPS_BIU_WDT_CR_RELOAD_SET(wdt_reload) | - IFXMIPS_BIU_WDT_CR_GEN); - - writel(wdt_cr, IFXMIPS_BIU_WDT_CR); - - printk("watchdog enabled\n"); - -out: - return retval; -} - -void -ifxmips_wdt_disable (void) -{ - writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); - writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2), IFXMIPS_BIU_WDT_CR); - - printk("watchdog disabled\n"); -} - -/* passed LPEN or DSEN */ -void -ifxmips_wdt_enable_feature (int en, int type) -{ - unsigned int wdt_cr = 0; - - writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); - - wdt_cr = readl(IFXMIPS_BIU_WDT_CR); - - if (en) - { - wdt_cr &= (~IFXMIPS_BIU_WDT_CR_PW_SET(0xff)); - wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | type); - } else { - wdt_cr &= (~IFXMIPS_BIU_WDT_CR_PW_SET(0xff) & ~type); - wdt_cr |= IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2); - } - - writel(wdt_cr, IFXMIPS_BIU_WDT_CR); -} - -void -ifxmips_wdt_prewarning_limit (int pwl) -{ - unsigned int wdt_cr = 0; - - wdt_cr = readl(IFXMIPS_BIU_WDT_CR); - writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); - - wdt_cr &= 0xf300ffff; - wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | IFXMIPS_BIU_WDT_CR_PWL_SET(pwl)); - - /* Set reload value in second password access */ - writel(wdt_cr, IFXMIPS_BIU_WDT_CR); -} - -void -ifxmips_wdt_set_clkdiv (int clkdiv) -{ - unsigned int wdt_cr = 0; - - wdt_cr = readl(IFXMIPS_BIU_WDT_CR); - writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); - - wdt_cr &= 0xfc00ffff; - wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | IFXMIPS_BIU_WDT_CR_CLKDIV_SET(clkdiv)); - - /* Set reload value in second password access */ - writel(wdt_cr, IFXMIPS_BIU_WDT_CR); -} - -static int -ifxmips_wdt_ioctl (struct inode *inode, struct file *file, unsigned int cmd, - unsigned long arg) -{ - int result = 0; - static int timeout = -1; - unsigned int user_arg; - - if ((cmd != IFXMIPS_WDT_IOC_STOP) && (cmd != IFXMIPS_WDT_IOC_PING) && (cmd != IFXMIPS_WDT_IOC_GET_STATUS)) - { - if (copy_from_user((void *) &user_arg, (void *) arg, sizeof (int))){ - result = -EINVAL; - goto out; - } - } - - switch (cmd) - { - case IFXMIPS_WDT_IOC_START: - if ((result = ifxmips_wdt_enable(user_arg)) < 0) - timeout = -1; - else - timeout = user_arg; - break; - - case IFXMIPS_WDT_IOC_STOP: - printk("disable watch dog timer\n"); - ifxmips_wdt_disable(); - break; - - case IFXMIPS_WDT_IOC_PING: - if (timeout < 0) - result = -EIO; - else - result = ifxmips_wdt_enable(timeout); - break; - - case IFXMIPS_WDT_IOC_GET_STATUS: - user_arg = readl(IFXMIPS_BIU_WDT_SR); - copy_to_user((int*)arg, (int*)&user_arg, sizeof(int)); - break; - - case IFXMIPS_WDT_IOC_SET_PWL: - ifxmips_wdt_prewarning_limit(user_arg); - break; - - case IFXMIPS_WDT_IOC_SET_DSEN: - ifxmips_wdt_enable_feature(user_arg, IFXMIPS_BIU_WDT_CR_DSEN); - break; - - case IFXMIPS_WDT_IOC_SET_LPEN: - ifxmips_wdt_enable_feature(user_arg, IFXMIPS_BIU_WDT_CR_LPEN); - break; - - case IFXMIPS_WDT_IOC_SET_CLKDIV: - ifxmips_wdt_set_clkdiv(user_arg); - break; - - default: - printk("unknown watchdog iotcl\n"); - } - -out: - return result; -} - -static int -ifxmips_wdt_open (struct inode *inode, struct file *file) -{ - if (ifxmips_wdt_inuse) - return -EBUSY; - - ifxmips_wdt_inuse = 1; - - return 0; -} - -static int -ifxmips_wdt_release (struct inode *inode, struct file *file) -{ - ifxmips_wdt_inuse = 0; - - return 0; -} - -int -ifxmips_wdt_register_proc_read (char *buf, char **start, off_t offset, int count, - int *eof, void *data) -{ - int len = 0; - - len += sprintf (buf + len, "IFXMIPS_BIU_WDT_PROC_READ\n"); - len += sprintf (buf + len, "IFXMIPS_BIU_WDT_CR(0x%08x) : 0x%08x\n", - (unsigned int)IFXMIPS_BIU_WDT_CR, readl(IFXMIPS_BIU_WDT_CR)); - len += sprintf (buf + len, "IFXMIPS_BIU_WDT_SR(0x%08x) : 0x%08x\n", - (unsigned int)IFXMIPS_BIU_WDT_SR, readl(IFXMIPS_BIU_WDT_SR)); - - *eof = 1; - - return len; -} - -static struct file_operations wdt_fops = { - .owner = THIS_MODULE, - .ioctl = ifxmips_wdt_ioctl, - .open = ifxmips_wdt_open, - .release = ifxmips_wdt_release, -}; - -int __init -ifxmips_wdt_init_module (void) -{ - ifxmips_wdt_major = register_chrdev(0, "wdt", &wdt_fops); - - if (ifxmips_wdt_major < 0) - { - printk("cannot register watchdog device\n"); - - return -EINVAL; - } - - create_proc_read_entry("ifxmips_wdt", 0, NULL, ifxmips_wdt_register_proc_read, NULL); - - printk("ifxmips watchdog loaded\n"); - - return 0; -} - -void -ifxmips_wdt_cleanup_module (void) -{ - unregister_chrdev(ifxmips_wdt_major, "wdt"); - remove_proc_entry("ifxmips_wdt", NULL); -} - -module_init(ifxmips_wdt_init_module); -module_exit(ifxmips_wdt_cleanup_module); diff --git a/target/linux/ifxmips/files/drivers/char/watchdog/ifxmips_wdt.c b/target/linux/ifxmips/files/drivers/char/watchdog/ifxmips_wdt.c new file mode 100644 index 0000000000..8fcbc88030 --- /dev/null +++ b/target/linux/ifxmips/files/drivers/char/watchdog/ifxmips_wdt.c @@ -0,0 +1,287 @@ +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2006 infineon + * Copyright (C) 2007 John Crispin + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +// TODO remove magic numbers and weirdo macros + +extern unsigned int ifxmips_get_fpi_hz (void); + +static int ifxmips_wdt_inuse = 0; +static int ifxmips_wdt_major = 0; + +int +ifxmips_wdt_enable (unsigned int timeout) +{ + unsigned int wdt_cr = 0; + unsigned int wdt_reload = 0; + unsigned int wdt_clkdiv, wdt_pwl, ffpi; + int retval = 0; + + /* clock divider & prewarning limit */ + wdt_clkdiv = 1 << (7 * IFXMIPS_BIU_WDT_CR_CLKDIV_GET(readl(IFXMIPS_BIU_WDT_CR))); + wdt_pwl = 0x8000 >> IFXMIPS_BIU_WDT_CR_PWL_GET(readl(IFXMIPS_BIU_WDT_CR)); + + //TODO + printk("WARNING FUNCTION CALL MISSING!!!"); + //ffpi = cgu_get_io_region_clock(); + printk("cpu clock = %d\n", ffpi); + + /* caculate reload value */ + wdt_reload = (timeout * (ffpi / wdt_clkdiv)) + wdt_pwl; + + printk("wdt_pwl=0x%x, wdt_clkdiv=%d, ffpi=%d, wdt_reload = 0x%x\n", + wdt_pwl, wdt_clkdiv, ffpi, wdt_reload); + + if (wdt_reload > 0xFFFF) + { + printk ("timeout too large %d\n", timeout); + retval = -EINVAL; + goto out; + } + + /* Write first part of password access */ + writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); + + wdt_cr = readl(IFXMIPS_BIU_WDT_CR); + wdt_cr &= (!IFXMIPS_BIU_WDT_CR_PW_SET(0xff) & + !IFXMIPS_BIU_WDT_CR_PWL_SET(0x3) & + !IFXMIPS_BIU_WDT_CR_CLKDIV_SET(0x3) & + !IFXMIPS_BIU_WDT_CR_RELOAD_SET(0xffff)); + + wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | + IFXMIPS_BIU_WDT_CR_PWL_SET(IFXMIPS_BIU_WDT_CR_PWL_GET(readl(IFXMIPS_BIU_WDT_CR))) | + IFXMIPS_BIU_WDT_CR_CLKDIV_SET(IFXMIPS_BIU_WDT_CR_CLKDIV_GET(readl(IFXMIPS_BIU_WDT_CR))) | + IFXMIPS_BIU_WDT_CR_RELOAD_SET(wdt_reload) | + IFXMIPS_BIU_WDT_CR_GEN); + + writel(wdt_cr, IFXMIPS_BIU_WDT_CR); + + printk("watchdog enabled\n"); + +out: + return retval; +} + +void +ifxmips_wdt_disable (void) +{ + writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); + writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2), IFXMIPS_BIU_WDT_CR); + + printk("watchdog disabled\n"); +} + +/* passed LPEN or DSEN */ +void +ifxmips_wdt_enable_feature (int en, int type) +{ + unsigned int wdt_cr = 0; + + writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); + + wdt_cr = readl(IFXMIPS_BIU_WDT_CR); + + if (en) + { + wdt_cr &= (~IFXMIPS_BIU_WDT_CR_PW_SET(0xff)); + wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | type); + } else { + wdt_cr &= (~IFXMIPS_BIU_WDT_CR_PW_SET(0xff) & ~type); + wdt_cr |= IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2); + } + + writel(wdt_cr, IFXMIPS_BIU_WDT_CR); +} + +void +ifxmips_wdt_prewarning_limit (int pwl) +{ + unsigned int wdt_cr = 0; + + wdt_cr = readl(IFXMIPS_BIU_WDT_CR); + writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); + + wdt_cr &= 0xf300ffff; + wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | IFXMIPS_BIU_WDT_CR_PWL_SET(pwl)); + + /* Set reload value in second password access */ + writel(wdt_cr, IFXMIPS_BIU_WDT_CR); +} + +void +ifxmips_wdt_set_clkdiv (int clkdiv) +{ + unsigned int wdt_cr = 0; + + wdt_cr = readl(IFXMIPS_BIU_WDT_CR); + writel(IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW1), IFXMIPS_BIU_WDT_CR); + + wdt_cr &= 0xfc00ffff; + wdt_cr |= (IFXMIPS_BIU_WDT_CR_PW_SET(IFXMIPS_WDT_PW2) | IFXMIPS_BIU_WDT_CR_CLKDIV_SET(clkdiv)); + + /* Set reload value in second password access */ + writel(wdt_cr, IFXMIPS_BIU_WDT_CR); +} + +static int +ifxmips_wdt_ioctl (struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + int result = 0; + static int timeout = -1; + unsigned int user_arg; + + if ((cmd != IFXMIPS_WDT_IOC_STOP) && (cmd != IFXMIPS_WDT_IOC_PING) && (cmd != IFXMIPS_WDT_IOC_GET_STATUS)) + { + if (copy_from_user((void *) &user_arg, (void *) arg, sizeof (int))){ + result = -EINVAL; + goto out; + } + } + + switch (cmd) + { + case IFXMIPS_WDT_IOC_START: + if ((result = ifxmips_wdt_enable(user_arg)) < 0) + timeout = -1; + else + timeout = user_arg; + break; + + case IFXMIPS_WDT_IOC_STOP: + printk("disable watch dog timer\n"); + ifxmips_wdt_disable(); + break; + + case IFXMIPS_WDT_IOC_PING: + if (timeout < 0) + result = -EIO; + else + result = ifxmips_wdt_enable(timeout); + break; + + case IFXMIPS_WDT_IOC_GET_STATUS: + user_arg = readl(IFXMIPS_BIU_WDT_SR); + copy_to_user((int*)arg, (int*)&user_arg, sizeof(int)); + break; + + case IFXMIPS_WDT_IOC_SET_PWL: + ifxmips_wdt_prewarning_limit(user_arg); + break; + + case IFXMIPS_WDT_IOC_SET_DSEN: + ifxmips_wdt_enable_feature(user_arg, IFXMIPS_BIU_WDT_CR_DSEN); + break; + + case IFXMIPS_WDT_IOC_SET_LPEN: + ifxmips_wdt_enable_feature(user_arg, IFXMIPS_BIU_WDT_CR_LPEN); + break; + + case IFXMIPS_WDT_IOC_SET_CLKDIV: + ifxmips_wdt_set_clkdiv(user_arg); + break; + + default: + printk("unknown watchdog iotcl\n"); + } + +out: + return result; +} + +static int +ifxmips_wdt_open (struct inode *inode, struct file *file) +{ + if (ifxmips_wdt_inuse) + return -EBUSY; + + ifxmips_wdt_inuse = 1; + + return 0; +} + +static int +ifxmips_wdt_release (struct inode *inode, struct file *file) +{ + ifxmips_wdt_inuse = 0; + + return 0; +} + +int +ifxmips_wdt_register_proc_read (char *buf, char **start, off_t offset, int count, + int *eof, void *data) +{ + int len = 0; + + len += sprintf (buf + len, "IFXMIPS_BIU_WDT_PROC_READ\n"); + len += sprintf (buf + len, "IFXMIPS_BIU_WDT_CR(0x%08x) : 0x%08x\n", + (unsigned int)IFXMIPS_BIU_WDT_CR, readl(IFXMIPS_BIU_WDT_CR)); + len += sprintf (buf + len, "IFXMIPS_BIU_WDT_SR(0x%08x) : 0x%08x\n", + (unsigned int)IFXMIPS_BIU_WDT_SR, readl(IFXMIPS_BIU_WDT_SR)); + + *eof = 1; + + return len; +} + +static struct file_operations wdt_fops = { + .owner = THIS_MODULE, + .ioctl = ifxmips_wdt_ioctl, + .open = ifxmips_wdt_open, + .release = ifxmips_wdt_release, +}; + +int __init +ifxmips_wdt_init_module (void) +{ + ifxmips_wdt_major = register_chrdev(0, "wdt", &wdt_fops); + + if (ifxmips_wdt_major < 0) + { + printk("cannot register watchdog device\n"); + + return -EINVAL; + } + + create_proc_read_entry("ifxmips_wdt", 0, NULL, ifxmips_wdt_register_proc_read, NULL); + + printk("ifxmips watchdog loaded\n"); + + return 0; +} + +void +ifxmips_wdt_cleanup_module (void) +{ + unregister_chrdev(ifxmips_wdt_major, "wdt"); + remove_proc_entry("ifxmips_wdt", NULL); +} + +module_init(ifxmips_wdt_init_module); +module_exit(ifxmips_wdt_cleanup_module); diff --git a/target/linux/ifxmips/files/drivers/mtd/maps/danube.c b/target/linux/ifxmips/files/drivers/mtd/maps/danube.c deleted file mode 100644 index 46ab528948..0000000000 --- a/target/linux/ifxmips/files/drivers/mtd/maps/danube.c +++ /dev/null @@ -1,194 +0,0 @@ -/* - * Driver for IFXMIPS flashmap - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE - * Copyright (C) 2007 John Crispin - */ - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -static struct map_info -danube_map = { - .name = "IFXMIPS_FLASH", - .bankwidth = 2, - .size = 0x400000, -}; - -static map_word -danube_read16 (struct map_info * map, unsigned long adr) -{ - map_word temp; - - adr ^= 2; - temp.x[0] = *((__u16 *) (map->virt + adr)); - - return temp; -} - -static void -danube_write16 (struct map_info *map, map_word d, unsigned long adr) -{ - adr ^= 2; - *((__u16 *) (map->virt + adr)) = d.x[0]; -} - -void -danube_copy_from (struct map_info *map, void *to, unsigned long from, ssize_t len) -{ - u8 *p; - u8 *to_8; - - from = (unsigned long) (from + map->virt); - p = (u8 *) from; - to_8 = (u8 *) to; - while(len--){ - *to_8++ = *p++; - } -} - -void -danube_copy_to (struct map_info *map, unsigned long to, const void *from, ssize_t len) -{ - u8 *p = (u8*) from; - u8 *to_8; - - to += (unsigned long) map->virt; - to_8 = (u8*)to; - while(len--){ - *p++ = *to_8++; - } -} - -static struct mtd_partition -danube_partitions[4] = { - { - name:"U-Boot", - offset:0x00000000, - size:0x00020000, - }, - { - name:"U-Boot-Env", - offset:0x00020000, - size:0x00010000, - }, - { - name:"kernel", - offset:0x00030000, - size:0x0, - }, - { - name:"rootfs", - offset:0x0, - size:0x0, - }, -}; - -#define IFXMIPS_FLASH_START 0x10000000 -#define IFXMIPS_FLASH_MAX 0x2000000 - -int -find_uImage_size (unsigned long start_offset){ - unsigned long temp; - - danube_copy_from(&danube_map, &temp, start_offset + 12, 4); - printk("kernel size is %ld \n", temp + 0x40); - return temp + 0x40; -} - -int -detect_squashfs_partition (unsigned long start_offset){ - unsigned long temp; - - danube_copy_from(&danube_map, &temp, start_offset, 4); - - return (temp == SQUASHFS_MAGIC); -} - -int __init -init_danube_mtd (void) -{ - struct mtd_info *danube_mtd = NULL; - struct mtd_partition *parts = NULL; - unsigned long uimage_size; - - writel(0x1d7ff, IFXMIPS_EBU_BUSCON0); - - danube_map.read = danube_read16; - danube_map.write = danube_write16; - danube_map.copy_from = danube_copy_from; - danube_map.copy_to = danube_copy_to; - - danube_map.phys = IFXMIPS_FLASH_START; - danube_map.virt = ioremap_nocache(IFXMIPS_FLASH_START, IFXMIPS_FLASH_MAX); - danube_map.size = IFXMIPS_FLASH_MAX; - if (!danube_map.virt) { - printk(KERN_WARNING "Failed to ioremap!\n"); - return -EIO; - } - - danube_mtd = (struct mtd_info *) do_map_probe("cfi_probe", &danube_map); - if (!danube_mtd) { - iounmap(danube_map.virt); - printk("probing failed\n"); - return -ENXIO; - } - - danube_mtd->owner = THIS_MODULE; - - uimage_size = find_uImage_size(danube_partitions[2].offset); - - if(detect_squashfs_partition(danube_partitions[2].offset + uimage_size)){ - printk("Found a squashfs following the uImage\n"); - } else { - uimage_size &= ~0xffff; - uimage_size += 0x10000; - } - - danube_partitions[2].size = uimage_size; - danube_partitions[3].offset = danube_partitions[2].offset + danube_partitions[2].size; - danube_partitions[3].size = ((danube_mtd->size >> 20) * 1024 * 1024) - danube_partitions[3].offset; - - parts = &danube_partitions[0]; - add_mtd_partitions(danube_mtd, parts, 4); - - printk("Added danube flash with %dMB\n", danube_mtd->size >> 20); - return 0; -} - -static void -__exit -cleanup_danube_mtd (void) -{ -} - -module_init (init_danube_mtd); -module_exit (cleanup_danube_mtd); - -MODULE_LICENSE ("GPL"); -MODULE_AUTHOR ("John Crispin "); -MODULE_DESCRIPTION ("MTD map driver for IFXMIPS boards"); diff --git a/target/linux/ifxmips/files/drivers/mtd/maps/ifxmips.c b/target/linux/ifxmips/files/drivers/mtd/maps/ifxmips.c new file mode 100644 index 0000000000..46ab528948 --- /dev/null +++ b/target/linux/ifxmips/files/drivers/mtd/maps/ifxmips.c @@ -0,0 +1,194 @@ +/* + * Driver for IFXMIPS flashmap + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2004 Liu Peng Infineon IFAP DC COM CPE + * Copyright (C) 2007 John Crispin + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +static struct map_info +danube_map = { + .name = "IFXMIPS_FLASH", + .bankwidth = 2, + .size = 0x400000, +}; + +static map_word +danube_read16 (struct map_info * map, unsigned long adr) +{ + map_word temp; + + adr ^= 2; + temp.x[0] = *((__u16 *) (map->virt + adr)); + + return temp; +} + +static void +danube_write16 (struct map_info *map, map_word d, unsigned long adr) +{ + adr ^= 2; + *((__u16 *) (map->virt + adr)) = d.x[0]; +} + +void +danube_copy_from (struct map_info *map, void *to, unsigned long from, ssize_t len) +{ + u8 *p; + u8 *to_8; + + from = (unsigned long) (from + map->virt); + p = (u8 *) from; + to_8 = (u8 *) to; + while(len--){ + *to_8++ = *p++; + } +} + +void +danube_copy_to (struct map_info *map, unsigned long to, const void *from, ssize_t len) +{ + u8 *p = (u8*) from; + u8 *to_8; + + to += (unsigned long) map->virt; + to_8 = (u8*)to; + while(len--){ + *p++ = *to_8++; + } +} + +static struct mtd_partition +danube_partitions[4] = { + { + name:"U-Boot", + offset:0x00000000, + size:0x00020000, + }, + { + name:"U-Boot-Env", + offset:0x00020000, + size:0x00010000, + }, + { + name:"kernel", + offset:0x00030000, + size:0x0, + }, + { + name:"rootfs", + offset:0x0, + size:0x0, + }, +}; + +#define IFXMIPS_FLASH_START 0x10000000 +#define IFXMIPS_FLASH_MAX 0x2000000 + +int +find_uImage_size (unsigned long start_offset){ + unsigned long temp; + + danube_copy_from(&danube_map, &temp, start_offset + 12, 4); + printk("kernel size is %ld \n", temp + 0x40); + return temp + 0x40; +} + +int +detect_squashfs_partition (unsigned long start_offset){ + unsigned long temp; + + danube_copy_from(&danube_map, &temp, start_offset, 4); + + return (temp == SQUASHFS_MAGIC); +} + +int __init +init_danube_mtd (void) +{ + struct mtd_info *danube_mtd = NULL; + struct mtd_partition *parts = NULL; + unsigned long uimage_size; + + writel(0x1d7ff, IFXMIPS_EBU_BUSCON0); + + danube_map.read = danube_read16; + danube_map.write = danube_write16; + danube_map.copy_from = danube_copy_from; + danube_map.copy_to = danube_copy_to; + + danube_map.phys = IFXMIPS_FLASH_START; + danube_map.virt = ioremap_nocache(IFXMIPS_FLASH_START, IFXMIPS_FLASH_MAX); + danube_map.size = IFXMIPS_FLASH_MAX; + if (!danube_map.virt) { + printk(KERN_WARNING "Failed to ioremap!\n"); + return -EIO; + } + + danube_mtd = (struct mtd_info *) do_map_probe("cfi_probe", &danube_map); + if (!danube_mtd) { + iounmap(danube_map.virt); + printk("probing failed\n"); + return -ENXIO; + } + + danube_mtd->owner = THIS_MODULE; + + uimage_size = find_uImage_size(danube_partitions[2].offset); + + if(detect_squashfs_partition(danube_partitions[2].offset + uimage_size)){ + printk("Found a squashfs following the uImage\n"); + } else { + uimage_size &= ~0xffff; + uimage_size += 0x10000; + } + + danube_partitions[2].size = uimage_size; + danube_partitions[3].offset = danube_partitions[2].offset + danube_partitions[2].size; + danube_partitions[3].size = ((danube_mtd->size >> 20) * 1024 * 1024) - danube_partitions[3].offset; + + parts = &danube_partitions[0]; + add_mtd_partitions(danube_mtd, parts, 4); + + printk("Added danube flash with %dMB\n", danube_mtd->size >> 20); + return 0; +} + +static void +__exit +cleanup_danube_mtd (void) +{ +} + +module_init (init_danube_mtd); +module_exit (cleanup_danube_mtd); + +MODULE_LICENSE ("GPL"); +MODULE_AUTHOR ("John Crispin "); +MODULE_DESCRIPTION ("MTD map driver for IFXMIPS boards"); diff --git a/target/linux/ifxmips/files/drivers/net/danube_mii0.c b/target/linux/ifxmips/files/drivers/net/danube_mii0.c deleted file mode 100644 index 50478bfe0a..0000000000 --- a/target/linux/ifxmips/files/drivers/net/danube_mii0.c +++ /dev/null @@ -1,433 +0,0 @@ -/* - * drivers/net/ifxmips_mii0.c - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. - * - * Copyright (C) 2005 Infineon - * - * Rewrite of Infineon IFXMips code, thanks to infineon for the support, - * software and hardware - * - * Copyright (C) 2007 John Crispin - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -static struct net_device ifxmips_mii0_dev; -static unsigned char u_boot_ethaddr[MAX_ADDR_LEN]; - -void -ifxmips_write_mdio (u32 phy_addr, u32 phy_reg, u16 phy_data) -{ - u32 val = MDIO_ACC_REQUEST | - ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) | - ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) | - phy_data; - - while (readl(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST); - writel(val, IFXMIPS_PPE32_MDIO_ACC); -} - -unsigned short -ifxmips_read_mdio (u32 phy_addr, u32 phy_reg) -{ - u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ | - ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) | - ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET); - - writel(val, IFXMIPS_PPE32_MDIO_ACC); - while (readl(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST){}; - val = readl(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK; - - return val; -} - -int -ifxmips_switch_open (struct net_device *dev) -{ - struct switch_priv* priv = (struct switch_priv*)dev->priv; - struct dma_device_info* dma_dev = priv->dma_device; - int i; - - for (i = 0; i < dma_dev->max_rx_chan_num; i++) - { - if ((dma_dev->rx_chan[i])->control == IFXMIPS_DMA_CH_ON) - (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]); - } - - netif_start_queue(dev); - - return 0; -} - -int -switch_release (struct net_device *dev){ - struct switch_priv* priv = (struct switch_priv*)dev->priv; - struct dma_device_info* dma_dev = priv->dma_device; - int i; - - for (i = 0; i < dma_dev->max_rx_chan_num; i++) - dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]); - - netif_stop_queue(dev); - - return 0; -} - -int -switch_hw_receive (struct net_device* dev,struct dma_device_info* dma_dev) -{ - struct switch_priv *priv = (struct switch_priv*)dev->priv; - unsigned char* buf = NULL; - struct sk_buff *skb = NULL; - int len = 0; - - len = dma_device_read(dma_dev, &buf, (void**)&skb); - - if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) - { - printk("packet too large %d\n",len); - goto switch_hw_receive_err_exit; - } - - /* remove CRC */ - len -= 4; - if (skb == NULL ) - { - printk("cannot restore pointer\n"); - goto switch_hw_receive_err_exit; - } - - if (len > (skb->end - skb->tail)) - { - printk("BUG, len:%d end:%p tail:%p\n", (len+4), skb->end, skb->tail); - goto switch_hw_receive_err_exit; - } - - skb_put(skb, len); - skb->dev = dev; - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - priv->stats.rx_packets++; - priv->stats.rx_bytes += len; - - return 0; - -switch_hw_receive_err_exit: - if (len == 0) - { - if(skb) - dev_kfree_skb_any(skb); - priv->stats.rx_errors++; - priv->stats.rx_dropped++; - - return -EIO; - } else { - return len; - } -} - -int -switch_hw_tx (char *buf, int len, struct net_device *dev) -{ - int ret = 0; - struct switch_priv *priv = dev->priv; - struct dma_device_info* dma_dev = priv->dma_device; - - ret = dma_device_write(dma_dev, buf, len, priv->skb); - - return ret; -} - -int -switch_tx (struct sk_buff *skb, struct net_device *dev) -{ - int len; - char *data; - struct switch_priv *priv = dev->priv; - struct dma_device_info* dma_dev = priv->dma_device; - - len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; - data = skb->data; - priv->skb = skb; - dev->trans_start = jiffies; - // TODO we got more than 1 dma channel, so we should do something intelligent - // here to select one - dma_dev->current_tx_chan = 0; - - wmb(); - - if (switch_hw_tx(data, len, dev) != len) - { - dev_kfree_skb_any(skb); - priv->stats.tx_errors++; - priv->stats.tx_dropped++; - } else { - priv->stats.tx_packets++; - priv->stats.tx_bytes+=len; - } - - return 0; -} - -void -switch_tx_timeout (struct net_device *dev) -{ - int i; - struct switch_priv* priv = (struct switch_priv*)dev->priv; - - priv->stats.tx_errors++; - - for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) - { - priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]); - } - - netif_wake_queue(dev); - - return; -} - -int -dma_intr_handler (struct dma_device_info* dma_dev, int status) -{ - int i; - - switch (status) - { - case RCV_INT: - switch_hw_receive(&ifxmips_mii0_dev, dma_dev); - break; - - case TX_BUF_FULL_INT: - printk("tx buffer full\n"); - netif_stop_queue(&ifxmips_mii0_dev); - for (i = 0; i < dma_dev->max_tx_chan_num; i++) - { - if ((dma_dev->tx_chan[i])->control==IFXMIPS_DMA_CH_ON) - dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]); - } - break; - - case TRANSMIT_CPT_INT: - for (i = 0; i < dma_dev->max_tx_chan_num; i++) - dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]); - - netif_wake_queue(&ifxmips_mii0_dev); - break; - } - - return 0; -} - -unsigned char* -ifxmips_etop_dma_buffer_alloc (int len, int *byte_offset, void **opt) -{ - unsigned char *buffer = NULL; - struct sk_buff *skb = NULL; - - skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE); - if (skb == NULL) - return NULL; - - buffer = (unsigned char*)(skb->data); - skb_reserve(skb, 2); - *(int*)opt = (int)skb; - *byte_offset = 2; - - return buffer; -} - -void -ifxmips_etop_dma_buffer_free (unsigned char *dataptr, void *opt) -{ - struct sk_buff *skb = NULL; - - if(opt == NULL) - { - kfree(dataptr); - } else { - skb = (struct sk_buff*)opt; - dev_kfree_skb_any(skb); - } -} - -static struct net_device_stats* -ifxmips_get_stats (struct net_device *dev) -{ - return (struct net_device_stats *)dev->priv; -} - -static int -switch_init (struct net_device *dev) -{ - u64 retval = 0; - int i; - struct switch_priv *priv; - - ether_setup(dev); - - printk("%s up\n", dev->name); - - dev->open = ifxmips_switch_open; - dev->stop = switch_release; - dev->hard_start_xmit = switch_tx; - dev->get_stats = ifxmips_get_stats; - dev->tx_timeout = switch_tx_timeout; - dev->watchdog_timeo = 10 * HZ; - dev->priv = kmalloc(sizeof(struct switch_priv), GFP_KERNEL); - - if (dev->priv == NULL) - return -ENOMEM; - - memset(dev->priv, 0, sizeof(struct switch_priv)); - priv = dev->priv; - - priv->dma_device = dma_device_reserve("PPE"); - - if (!priv->dma_device){ - BUG(); - return -ENODEV; - } - - priv->dma_device->buffer_alloc = &ifxmips_etop_dma_buffer_alloc; - priv->dma_device->buffer_free = &ifxmips_etop_dma_buffer_free; - priv->dma_device->intr_handler = &dma_intr_handler; - priv->dma_device->max_rx_chan_num = 4; - - for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) - { - priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE; - priv->dma_device->rx_chan[i]->control = IFXMIPS_DMA_CH_ON; - } - - for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) - { - if(i == 0) - priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_ON; - else - priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_OFF; - } - - dma_device_register(priv->dma_device); - - /*read the mac address from the mac table and put them into the mac table.*/ - for (i = 0; i < 6; i++) - { - retval += u_boot_ethaddr[i]; - } - - //TODO - /* ethaddr not set in u-boot ? */ - if (retval == 0) - { - printk("use default MAC address\n"); - dev->dev_addr[0] = 0x00; - dev->dev_addr[1] = 0x11; - dev->dev_addr[2] = 0x22; - dev->dev_addr[3] = 0x33; - dev->dev_addr[4] = 0x44; - dev->dev_addr[5] = 0x55; - } else { - for (i = 0; i < 6; i++) - dev->dev_addr[i] = u_boot_ethaddr[i]; - } - - return 0; -} - -static void -ifxmips_sw_chip_init (int mode) -{ - ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_DMA); - ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_PPE); - - if(mode == REV_MII_MODE) - writel((readl(IFXMIPS_PPE32_CFG) & PPE32_MII_MASK) | PPE32_MII_REVERSE, IFXMIPS_PPE32_CFG); - else if(mode == MII_MODE) - writel((readl(IFXMIPS_PPE32_CFG) & PPE32_MII_MASK) | PPE32_MII_NORMAL, IFXMIPS_PPE32_CFG); - - writel(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, IFXMIPS_PPE32_IG_PLEN_CTRL); - - writel(PPE32_CGEN, IFXMIPS_PPE32_ENET_MAC_CFG); - - wmb(); -} - -int __init -switch_init_module(void) -{ - int result = 0; - - ifxmips_mii0_dev.init = switch_init; - - strcpy(ifxmips_mii0_dev.name, "eth%d"); - SET_MODULE_OWNER(dev); - - result = register_netdev(&ifxmips_mii0_dev); - if (result) - { - printk("error %i registering device \"%s\"\n", result, ifxmips_mii0_dev.name); - goto out; - } - - /* ifxmips eval kit connects the phy/switch in REV mode */ - ifxmips_sw_chip_init(REV_MII_MODE); - printk("ifxmips MAC driver loaded!\n"); - -out: - return result; -} - -static void __exit -switch_cleanup(void) -{ - struct switch_priv *priv = (struct switch_priv*)ifxmips_mii0_dev.priv; - - printk("ifxmips_mii0 cleanup\n"); - - dma_device_unregister(priv->dma_device); - dma_device_release(priv->dma_device); - kfree(priv->dma_device); - kfree(ifxmips_mii0_dev.priv); - unregister_netdev(&ifxmips_mii0_dev); - - return; -} - -module_init(switch_init_module); -module_exit(switch_cleanup); diff --git a/target/linux/ifxmips/files/drivers/net/ifxmips_mii0.c b/target/linux/ifxmips/files/drivers/net/ifxmips_mii0.c new file mode 100644 index 0000000000..50478bfe0a --- /dev/null +++ b/target/linux/ifxmips/files/drivers/net/ifxmips_mii0.c @@ -0,0 +1,433 @@ +/* + * drivers/net/ifxmips_mii0.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + * + * Copyright (C) 2005 Infineon + * + * Rewrite of Infineon IFXMips code, thanks to infineon for the support, + * software and hardware + * + * Copyright (C) 2007 John Crispin + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct net_device ifxmips_mii0_dev; +static unsigned char u_boot_ethaddr[MAX_ADDR_LEN]; + +void +ifxmips_write_mdio (u32 phy_addr, u32 phy_reg, u16 phy_data) +{ + u32 val = MDIO_ACC_REQUEST | + ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) | + ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET) | + phy_data; + + while (readl(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST); + writel(val, IFXMIPS_PPE32_MDIO_ACC); +} + +unsigned short +ifxmips_read_mdio (u32 phy_addr, u32 phy_reg) +{ + u32 val = MDIO_ACC_REQUEST | MDIO_ACC_READ | + ((phy_addr & MDIO_ACC_ADDR_MASK) << MDIO_ACC_ADDR_OFFSET) | + ((phy_reg & MDIO_ACC_REG_MASK) << MDIO_ACC_REG_OFFSET); + + writel(val, IFXMIPS_PPE32_MDIO_ACC); + while (readl(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_REQUEST){}; + val = readl(IFXMIPS_PPE32_MDIO_ACC) & MDIO_ACC_VAL_MASK; + + return val; +} + +int +ifxmips_switch_open (struct net_device *dev) +{ + struct switch_priv* priv = (struct switch_priv*)dev->priv; + struct dma_device_info* dma_dev = priv->dma_device; + int i; + + for (i = 0; i < dma_dev->max_rx_chan_num; i++) + { + if ((dma_dev->rx_chan[i])->control == IFXMIPS_DMA_CH_ON) + (dma_dev->rx_chan[i])->open(dma_dev->rx_chan[i]); + } + + netif_start_queue(dev); + + return 0; +} + +int +switch_release (struct net_device *dev){ + struct switch_priv* priv = (struct switch_priv*)dev->priv; + struct dma_device_info* dma_dev = priv->dma_device; + int i; + + for (i = 0; i < dma_dev->max_rx_chan_num; i++) + dma_dev->rx_chan[i]->close(dma_dev->rx_chan[i]); + + netif_stop_queue(dev); + + return 0; +} + +int +switch_hw_receive (struct net_device* dev,struct dma_device_info* dma_dev) +{ + struct switch_priv *priv = (struct switch_priv*)dev->priv; + unsigned char* buf = NULL; + struct sk_buff *skb = NULL; + int len = 0; + + len = dma_device_read(dma_dev, &buf, (void**)&skb); + + if (len >= ETHERNET_PACKET_DMA_BUFFER_SIZE) + { + printk("packet too large %d\n",len); + goto switch_hw_receive_err_exit; + } + + /* remove CRC */ + len -= 4; + if (skb == NULL ) + { + printk("cannot restore pointer\n"); + goto switch_hw_receive_err_exit; + } + + if (len > (skb->end - skb->tail)) + { + printk("BUG, len:%d end:%p tail:%p\n", (len+4), skb->end, skb->tail); + goto switch_hw_receive_err_exit; + } + + skb_put(skb, len); + skb->dev = dev; + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + priv->stats.rx_packets++; + priv->stats.rx_bytes += len; + + return 0; + +switch_hw_receive_err_exit: + if (len == 0) + { + if(skb) + dev_kfree_skb_any(skb); + priv->stats.rx_errors++; + priv->stats.rx_dropped++; + + return -EIO; + } else { + return len; + } +} + +int +switch_hw_tx (char *buf, int len, struct net_device *dev) +{ + int ret = 0; + struct switch_priv *priv = dev->priv; + struct dma_device_info* dma_dev = priv->dma_device; + + ret = dma_device_write(dma_dev, buf, len, priv->skb); + + return ret; +} + +int +switch_tx (struct sk_buff *skb, struct net_device *dev) +{ + int len; + char *data; + struct switch_priv *priv = dev->priv; + struct dma_device_info* dma_dev = priv->dma_device; + + len = skb->len < ETH_ZLEN ? ETH_ZLEN : skb->len; + data = skb->data; + priv->skb = skb; + dev->trans_start = jiffies; + // TODO we got more than 1 dma channel, so we should do something intelligent + // here to select one + dma_dev->current_tx_chan = 0; + + wmb(); + + if (switch_hw_tx(data, len, dev) != len) + { + dev_kfree_skb_any(skb); + priv->stats.tx_errors++; + priv->stats.tx_dropped++; + } else { + priv->stats.tx_packets++; + priv->stats.tx_bytes+=len; + } + + return 0; +} + +void +switch_tx_timeout (struct net_device *dev) +{ + int i; + struct switch_priv* priv = (struct switch_priv*)dev->priv; + + priv->stats.tx_errors++; + + for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) + { + priv->dma_device->tx_chan[i]->disable_irq(priv->dma_device->tx_chan[i]); + } + + netif_wake_queue(dev); + + return; +} + +int +dma_intr_handler (struct dma_device_info* dma_dev, int status) +{ + int i; + + switch (status) + { + case RCV_INT: + switch_hw_receive(&ifxmips_mii0_dev, dma_dev); + break; + + case TX_BUF_FULL_INT: + printk("tx buffer full\n"); + netif_stop_queue(&ifxmips_mii0_dev); + for (i = 0; i < dma_dev->max_tx_chan_num; i++) + { + if ((dma_dev->tx_chan[i])->control==IFXMIPS_DMA_CH_ON) + dma_dev->tx_chan[i]->enable_irq(dma_dev->tx_chan[i]); + } + break; + + case TRANSMIT_CPT_INT: + for (i = 0; i < dma_dev->max_tx_chan_num; i++) + dma_dev->tx_chan[i]->disable_irq(dma_dev->tx_chan[i]); + + netif_wake_queue(&ifxmips_mii0_dev); + break; + } + + return 0; +} + +unsigned char* +ifxmips_etop_dma_buffer_alloc (int len, int *byte_offset, void **opt) +{ + unsigned char *buffer = NULL; + struct sk_buff *skb = NULL; + + skb = dev_alloc_skb(ETHERNET_PACKET_DMA_BUFFER_SIZE); + if (skb == NULL) + return NULL; + + buffer = (unsigned char*)(skb->data); + skb_reserve(skb, 2); + *(int*)opt = (int)skb; + *byte_offset = 2; + + return buffer; +} + +void +ifxmips_etop_dma_buffer_free (unsigned char *dataptr, void *opt) +{ + struct sk_buff *skb = NULL; + + if(opt == NULL) + { + kfree(dataptr); + } else { + skb = (struct sk_buff*)opt; + dev_kfree_skb_any(skb); + } +} + +static struct net_device_stats* +ifxmips_get_stats (struct net_device *dev) +{ + return (struct net_device_stats *)dev->priv; +} + +static int +switch_init (struct net_device *dev) +{ + u64 retval = 0; + int i; + struct switch_priv *priv; + + ether_setup(dev); + + printk("%s up\n", dev->name); + + dev->open = ifxmips_switch_open; + dev->stop = switch_release; + dev->hard_start_xmit = switch_tx; + dev->get_stats = ifxmips_get_stats; + dev->tx_timeout = switch_tx_timeout; + dev->watchdog_timeo = 10 * HZ; + dev->priv = kmalloc(sizeof(struct switch_priv), GFP_KERNEL); + + if (dev->priv == NULL) + return -ENOMEM; + + memset(dev->priv, 0, sizeof(struct switch_priv)); + priv = dev->priv; + + priv->dma_device = dma_device_reserve("PPE"); + + if (!priv->dma_device){ + BUG(); + return -ENODEV; + } + + priv->dma_device->buffer_alloc = &ifxmips_etop_dma_buffer_alloc; + priv->dma_device->buffer_free = &ifxmips_etop_dma_buffer_free; + priv->dma_device->intr_handler = &dma_intr_handler; + priv->dma_device->max_rx_chan_num = 4; + + for (i = 0; i < priv->dma_device->max_rx_chan_num; i++) + { + priv->dma_device->rx_chan[i]->packet_size = ETHERNET_PACKET_DMA_BUFFER_SIZE; + priv->dma_device->rx_chan[i]->control = IFXMIPS_DMA_CH_ON; + } + + for (i = 0; i < priv->dma_device->max_tx_chan_num; i++) + { + if(i == 0) + priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_ON; + else + priv->dma_device->tx_chan[i]->control = IFXMIPS_DMA_CH_OFF; + } + + dma_device_register(priv->dma_device); + + /*read the mac address from the mac table and put them into the mac table.*/ + for (i = 0; i < 6; i++) + { + retval += u_boot_ethaddr[i]; + } + + //TODO + /* ethaddr not set in u-boot ? */ + if (retval == 0) + { + printk("use default MAC address\n"); + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x11; + dev->dev_addr[2] = 0x22; + dev->dev_addr[3] = 0x33; + dev->dev_addr[4] = 0x44; + dev->dev_addr[5] = 0x55; + } else { + for (i = 0; i < 6; i++) + dev->dev_addr[i] = u_boot_ethaddr[i]; + } + + return 0; +} + +static void +ifxmips_sw_chip_init (int mode) +{ + ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_DMA); + ifxmips_pmu_enable(IFXMIPS_PMU_PWDCR_PPE); + + if(mode == REV_MII_MODE) + writel((readl(IFXMIPS_PPE32_CFG) & PPE32_MII_MASK) | PPE32_MII_REVERSE, IFXMIPS_PPE32_CFG); + else if(mode == MII_MODE) + writel((readl(IFXMIPS_PPE32_CFG) & PPE32_MII_MASK) | PPE32_MII_NORMAL, IFXMIPS_PPE32_CFG); + + writel(PPE32_PLEN_UNDER | PPE32_PLEN_OVER, IFXMIPS_PPE32_IG_PLEN_CTRL); + + writel(PPE32_CGEN, IFXMIPS_PPE32_ENET_MAC_CFG); + + wmb(); +} + +int __init +switch_init_module(void) +{ + int result = 0; + + ifxmips_mii0_dev.init = switch_init; + + strcpy(ifxmips_mii0_dev.name, "eth%d"); + SET_MODULE_OWNER(dev); + + result = register_netdev(&ifxmips_mii0_dev); + if (result) + { + printk("error %i registering device \"%s\"\n", result, ifxmips_mii0_dev.name); + goto out; + } + + /* ifxmips eval kit connects the phy/switch in REV mode */ + ifxmips_sw_chip_init(REV_MII_MODE); + printk("ifxmips MAC driver loaded!\n"); + +out: + return result; +} + +static void __exit +switch_cleanup(void) +{ + struct switch_priv *priv = (struct switch_priv*)ifxmips_mii0_dev.priv; + + printk("ifxmips_mii0 cleanup\n"); + + dma_device_unregister(priv->dma_device); + dma_device_release(priv->dma_device); + kfree(priv->dma_device); + kfree(ifxmips_mii0_dev.priv); + unregister_netdev(&ifxmips_mii0_dev); + + return; +} + +module_init(switch_init_module); +module_exit(switch_cleanup); diff --git a/target/linux/ifxmips/files/drivers/serial/danube_asc.c b/target/linux/ifxmips/files/drivers/serial/danube_asc.c deleted file mode 100644 index b191241dbf..0000000000 --- a/target/linux/ifxmips/files/drivers/serial/danube_asc.c +++ /dev/null @@ -1,608 +0,0 @@ -/* - * Driver for IFXMIPSASC serial ports - * - * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - * - * Copyright (C) 2004 Infineon IFAP DC COM CPE - * Copyright (C) 2007 Felix Fietkau - * Copyright (C) 2007 John Crispin - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define PORT_IFXMIPSASC 111 - -#include - -#define UART_DUMMY_UER_RX 1 - -static void ifxmipsasc_tx_chars(struct uart_port *port); -extern void prom_printf(const char * fmt, ...); -static struct uart_port ifxmipsasc_port; -static struct uart_driver ifxmipsasc_reg; -static unsigned int uartclk = 0; -extern unsigned int ifxmips_get_fpi_hz(void); - -static void -ifxmipsasc_stop_tx (struct uart_port *port) -{ - /* fifo underrun shuts up after firing once */ - return; -} - -static void -ifxmipsasc_start_tx (struct uart_port *port) -{ - unsigned long flags; - - local_irq_save(flags); - ifxmipsasc_tx_chars(port); - local_irq_restore(flags); - - return; -} - -static void -ifxmipsasc_stop_rx (struct uart_port *port) -{ - /* clear the RX enable bit */ - writel(ASCWHBSTATE_CLRREN, IFXMIPS_ASC1_WHBSTATE); -} - -static void -ifxmipsasc_enable_ms (struct uart_port *port) -{ - /* no modem signals */ - return; -} - -static void -ifxmipsasc_rx_chars (struct uart_port *port) -{ - struct tty_struct *tty = port->info->tty; - unsigned int ch = 0, rsr = 0, fifocnt; - - fifocnt = readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_RXFFLMASK; - while (fifocnt--) - { - u8 flag = TTY_NORMAL; - ch = readl(IFXMIPS_ASC1_RBUF); - rsr = (readl(IFXMIPS_ASC1_STATE) & ASCSTATE_ANY) | UART_DUMMY_UER_RX; - tty_flip_buffer_push(tty); - port->icount.rx++; - - /* - * Note that the error handling code is - * out of the main execution path - */ - if (rsr & ASCSTATE_ANY) { - if (rsr & ASCSTATE_PE) { - port->icount.parity++; - writel(readl(IFXMIPS_ASC1_WHBSTATE) | ASCWHBSTATE_CLRPE, IFXMIPS_ASC1_WHBSTATE); - } else if (rsr & ASCSTATE_FE) { - port->icount.frame++; - writel(readl(IFXMIPS_ASC1_WHBSTATE) | ASCWHBSTATE_CLRFE, IFXMIPS_ASC1_WHBSTATE); - } - if (rsr & ASCSTATE_ROE) { - port->icount.overrun++; - writel(readl(IFXMIPS_ASC1_WHBSTATE) | ASCWHBSTATE_CLRROE, IFXMIPS_ASC1_WHBSTATE); - } - - rsr &= port->read_status_mask; - - if (rsr & ASCSTATE_PE) - flag = TTY_PARITY; - else if (rsr & ASCSTATE_FE) - flag = TTY_FRAME; - } - - if ((rsr & port->ignore_status_mask) == 0) - tty_insert_flip_char(tty, ch, flag); - - if (rsr & ASCSTATE_ROE) - /* - * Overrun is special, since it's reported - * immediately, and doesn't affect the current - * character - */ - tty_insert_flip_char(tty, 0, TTY_OVERRUN); - } - if (ch != 0) - tty_flip_buffer_push(tty); - - return; -} - - -static void -ifxmipsasc_tx_chars (struct uart_port *port) -{ - struct circ_buf *xmit = &port->info->xmit; - - if (uart_tx_stopped(port)) { - ifxmipsasc_stop_tx(port); - return; - } - - while(((readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_TXFFLMASK) - >> ASCFSTAT_TXFFLOFF) != IFXMIPSASC_TXFIFO_FULL) - { - if (port->x_char) { - writel(port->x_char, IFXMIPS_ASC1_TBUF); - port->icount.tx++; - port->x_char = 0; - continue; - } - - if (uart_circ_empty(xmit)) - break; - - writel(port->info->xmit.buf[port->info->xmit.tail], IFXMIPS_ASC1_TBUF); - xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); - port->icount.tx++; - } - - if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) - uart_write_wakeup(port); -} - -static irqreturn_t -ifxmipsasc_tx_int (int irq, void *port) -{ - writel(ASC_IRNCR_TIR, IFXMIPS_ASC1_IRNCR); - ifxmipsasc_start_tx(port); - mask_and_ack_ifxmips_irq(irq); - - return IRQ_HANDLED; -} - -static irqreturn_t -ifxmipsasc_er_int (int irq, void *port) -{ - /* clear any pending interrupts */ - writel(readl(IFXMIPS_ASC1_WHBSTATE) | ASCWHBSTATE_CLRPE | - ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE, IFXMIPS_ASC1_WHBSTATE); - - return IRQ_HANDLED; -} - -static irqreturn_t -ifxmipsasc_rx_int (int irq, void *port) -{ - writel(ASC_IRNCR_RIR, IFXMIPS_ASC1_IRNCR); - ifxmipsasc_rx_chars((struct uart_port *) port); - mask_and_ack_ifxmips_irq(irq); - - return IRQ_HANDLED; -} - -static unsigned int -ifxmipsasc_tx_empty (struct uart_port *port) -{ - int status; - - status = readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_TXFFLMASK; - - return status ? 0 : TIOCSER_TEMT; -} - -static unsigned int -ifxmipsasc_get_mctrl (struct uart_port *port) -{ - return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR; -} - -static void -ifxmipsasc_set_mctrl (struct uart_port *port, u_int mctrl) -{ - return; -} - -static void -ifxmipsasc_break_ctl (struct uart_port *port, int break_state) -{ - return; -} - -static void -ifxmipsasc1_hw_init (void) -{ - /* this setup was probably already done in ROM/u-boot but we do it again*/ - /* TODO: GPIO pins are multifunction */ - writel(readl(IFXMIPS_ASC1_CLC) & ~IFXMIPS_ASC1_CLC_DISS, IFXMIPS_ASC1_CLC); - writel((readl(IFXMIPS_ASC1_CLC) & ~ASCCLC_RMCMASK) | (1 << ASCCLC_RMCOFFSET), IFXMIPS_ASC1_CLC); - writel(0, IFXMIPS_ASC1_PISEL); - writel(((IFXMIPSASC_TXFIFO_FL << ASCTXFCON_TXFITLOFF) & - ASCTXFCON_TXFITLMASK) | ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, IFXMIPS_ASC1_TXFCON); - writel(((IFXMIPSASC_RXFIFO_FL << ASCRXFCON_RXFITLOFF) & - ASCRXFCON_RXFITLMASK) | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, IFXMIPS_ASC1_RXFCON); - wmb (); - - /*framing, overrun, enable */ - writel(readl(IFXMIPS_ASC1_CON) | ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN, - IFXMIPS_ASC1_CON); -} - -static int -ifxmipsasc_startup (struct uart_port *port) -{ - unsigned long flags; - int retval; - - /* this assumes: CON.BRS = CON.FDE = 0 */ - if (uartclk == 0) - uartclk = ifxmips_get_fpi_hz(); - - ifxmipsasc_port.uartclk = uartclk; - - ifxmipsasc1_hw_init(); - - local_irq_save(flags); - - retval = request_irq(IFXMIPSASC1_RIR, ifxmipsasc_rx_int, IRQF_DISABLED, "asc_rx", port); - if (retval){ - printk("failed to request ifxmipsasc_rx_int\n"); - return retval; - } - - retval = request_irq(IFXMIPSASC1_TIR, ifxmipsasc_tx_int, IRQF_DISABLED, "asc_tx", port); - if (retval){ - printk("failed to request ifxmipsasc_tx_int\n"); - goto err1; - } - - retval = request_irq(IFXMIPSASC1_EIR, ifxmipsasc_er_int, IRQF_DISABLED, "asc_er", port); - if (retval){ - printk("failed to request ifxmipsasc_er_int\n"); - goto err2; - } - - writel(ASC_IRNREN_RX_BUF | ASC_IRNREN_TX_BUF | ASC_IRNREN_ERR | ASC_IRNREN_TX, - IFXMIPS_ASC1_IRNREN); - - local_irq_restore(flags); - - return 0; - -err2: - free_irq(IFXMIPSASC1_TIR, port); - -err1: - free_irq(IFXMIPSASC1_RIR, port); - local_irq_restore(flags); - - return retval; -} - -static void -ifxmipsasc_shutdown (struct uart_port *port) -{ - free_irq(IFXMIPSASC1_RIR, port); - free_irq(IFXMIPSASC1_TIR, port); - free_irq(IFXMIPSASC1_EIR, port); - /* - * disable the baudrate generator to disable the ASC - */ - writel(0, IFXMIPS_ASC1_CON); - - /* flush and then disable the fifos */ - writel(readl(IFXMIPS_ASC1_RXFCON) | ASCRXFCON_RXFFLU, IFXMIPS_ASC1_RXFCON); - writel(readl(IFXMIPS_ASC1_RXFCON) & ~ASCRXFCON_RXFEN, IFXMIPS_ASC1_RXFCON); - writel(readl(IFXMIPS_ASC1_TXFCON) | ASCTXFCON_TXFFLU, IFXMIPS_ASC1_TXFCON); - writel(readl(IFXMIPS_ASC1_TXFCON) & ~ASCTXFCON_TXFEN, IFXMIPS_ASC1_TXFCON); -} - -static void ifxmipsasc_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old) -{ - unsigned int cflag; - unsigned int iflag; - unsigned int quot; - unsigned int baud; - unsigned int con = 0; - unsigned long flags; - - cflag = new->c_cflag; - iflag = new->c_iflag; - - /* byte size and parity */ - switch (cflag & CSIZE) { - case CS7: - con = ASCCON_M_7ASYNC; - break; - - case CS5: - case CS6: - default: - con = ASCCON_M_8ASYNC; - break; - } - - if (cflag & CSTOPB) - con |= ASCCON_STP; - - if (cflag & PARENB) { - if (!(cflag & PARODD)) - con &= ~ASCCON_ODD; - else - con |= ASCCON_ODD; - } - - port->read_status_mask = ASCSTATE_ROE; - if (iflag & INPCK) - port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE; - - port->ignore_status_mask = 0; - if (iflag & IGNPAR) - port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE; - - if (iflag & IGNBRK) { - /* - * If we're ignoring parity and break indicators, - * ignore overruns too (for real raw support). - */ - if (iflag & IGNPAR) - port->ignore_status_mask |= ASCSTATE_ROE; - } - - if ((cflag & CREAD) == 0) - port->ignore_status_mask |= UART_DUMMY_UER_RX; - - /* set error signals - framing, parity and overrun, enable receiver */ - con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN; - - local_irq_save(flags); - - /* set up CON */ - writel(readl(IFXMIPS_ASC1_CON) | con, IFXMIPS_ASC1_CON); - - /* Set baud rate - take a divider of 2 into account */ - baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); - quot = uart_get_divisor(port, baud); - quot = quot / 2 - 1; - - /* disable the baudrate generator */ - writel(readl(IFXMIPS_ASC1_CON) & ~ASCCON_R, IFXMIPS_ASC1_CON); - - /* make sure the fractional divider is off */ - writel(readl(IFXMIPS_ASC1_CON) & ~ASCCON_FDE, IFXMIPS_ASC1_CON); - - /* set up to use divisor of 2 */ - writel(readl(IFXMIPS_ASC1_CON) & ~ASCCON_BRS, IFXMIPS_ASC1_CON); - - /* now we can write the new baudrate into the register */ - writel(quot, IFXMIPS_ASC1_BG); - - /* turn the baudrate generator back on */ - writel(readl(IFXMIPS_ASC1_CON) | ASCCON_R, IFXMIPS_ASC1_CON); - - /* enable rx */ - writel(ASCWHBSTATE_SETREN, IFXMIPS_ASC1_WHBSTATE); - - local_irq_restore(flags); -} - -static const char* -ifxmipsasc_type (struct uart_port *port) -{ - return port->type == PORT_IFXMIPSASC ? "IFXMIPSASC" : NULL; -} - -static void -ifxmipsasc_release_port (struct uart_port *port) -{ - return; -} - -static int -ifxmipsasc_request_port (struct uart_port *port) -{ - return 0; -} - -static void -ifxmipsasc_config_port (struct uart_port *port, int flags) -{ - if (flags & UART_CONFIG_TYPE) { - port->type = PORT_IFXMIPSASC; - ifxmipsasc_request_port(port); - } -} - -static int -ifxmipsasc_verify_port (struct uart_port *port, struct serial_struct *ser) -{ - int ret = 0; - if (ser->type != PORT_UNKNOWN && ser->type != PORT_IFXMIPSASC) - ret = -EINVAL; - if (ser->irq < 0 || ser->irq >= NR_IRQS) - ret = -EINVAL; - if (ser->baud_base < 9600) - ret = -EINVAL; - return ret; -} - -static struct uart_ops ifxmipsasc_pops = { - .tx_empty = ifxmipsasc_tx_empty, - .set_mctrl = ifxmipsasc_set_mctrl, - .get_mctrl = ifxmipsasc_get_mctrl, - .stop_tx = ifxmipsasc_stop_tx, - .start_tx = ifxmipsasc_start_tx, - .stop_rx = ifxmipsasc_stop_rx, - .enable_ms = ifxmipsasc_enable_ms, - .break_ctl = ifxmipsasc_break_ctl, - .startup = ifxmipsasc_startup, - .shutdown = ifxmipsasc_shutdown, - .set_termios = ifxmipsasc_set_termios, - .type = ifxmipsasc_type, - .release_port = ifxmipsasc_release_port, - .request_port = ifxmipsasc_request_port, - .config_port = ifxmipsasc_config_port, - .verify_port = ifxmipsasc_verify_port, -}; - -static struct uart_port ifxmipsasc_port = { - membase: (void *)IFXMIPS_ASC1_BASE_ADDR, - mapbase: IFXMIPS_ASC1_BASE_ADDR, - iotype: SERIAL_IO_MEM, - irq: IFXMIPSASC1_RIR, - uartclk: 0, - fifosize: 16, - unused: {IFXMIPSASC1_TIR, IFXMIPSASC1_EIR}, - type: PORT_IFXMIPSASC, - ops: &ifxmipsasc_pops, - flags: ASYNC_BOOT_AUTOCONF, -}; - -static void -ifxmipsasc_console_write (struct console *co, const char *s, u_int count) -{ - int i, fifocnt; - unsigned long flags; - - local_irq_save(flags); - for (i = 0; i < count; i++) - { - /* wait until the FIFO is not full */ - do - { - fifocnt = (readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_TXFFLMASK) - >> ASCFSTAT_TXFFLOFF; - } while (fifocnt == IFXMIPSASC_TXFIFO_FULL); - - if (s[i] == '\0') - { - break; - } - - if (s[i] == '\n') - { - writel('\r', IFXMIPS_ASC1_TBUF); - do - { - fifocnt = (readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_TXFFLMASK) - >> ASCFSTAT_TXFFLOFF; - } while (fifocnt == IFXMIPSASC_TXFIFO_FULL); - } - writel(s[i], IFXMIPS_ASC1_TBUF); - } - - local_irq_restore(flags); -} - -static int __init -ifxmipsasc_console_setup (struct console *co, char *options) -{ - struct uart_port *port; - int baud = 115200; - int bits = 8; - int parity = 'n'; - int flow = 'n'; - - if (uartclk == 0) - uartclk = ifxmips_get_fpi_hz(); - co->index = 0; - port = &ifxmipsasc_port; - ifxmipsasc_port.uartclk = uartclk; - ifxmipsasc_port.type = PORT_IFXMIPSASC; - - if (options){ - uart_parse_options(options, &baud, &parity, &bits, &flow); - } - - return uart_set_options(port, co, baud, parity, bits, flow); -} - -static struct uart_driver ifxmipsasc_reg; -static struct console ifxmipsasc_console = { - name: "ttyS", - write: ifxmipsasc_console_write, - device: uart_console_device, - setup: ifxmipsasc_console_setup, - flags: CON_PRINTBUFFER, - index: -1, - data: &ifxmipsasc_reg, -}; - -static int __init -ifxmipsasc_console_init (void) -{ - register_console(&ifxmipsasc_console); - return 0; -} -console_initcall(ifxmipsasc_console_init); - -static struct uart_driver ifxmipsasc_reg = { - .owner = THIS_MODULE, - .driver_name = "serial", - .dev_name = "ttyS", - .major = TTY_MAJOR, - .minor = 64, - .nr = 1, - .cons = &ifxmipsasc_console, -}; - -static int __init -ifxmipsasc_init (void) -{ - unsigned char res; - - uart_register_driver(&ifxmipsasc_reg); - res = uart_add_one_port(&ifxmipsasc_reg, &ifxmipsasc_port); - - return res; -} - -static void __exit -ifxmipsasc_exit (void) -{ - uart_unregister_driver(&ifxmipsasc_reg); -} - -module_init(ifxmipsasc_init); -module_exit(ifxmipsasc_exit); - -MODULE_AUTHOR("John Crispin "); -MODULE_DESCRIPTION("MIPS IFXMips serial port driver"); -MODULE_LICENSE("GPL"); diff --git a/target/linux/ifxmips/files/drivers/serial/ifxmips_asc.c b/target/linux/ifxmips/files/drivers/serial/ifxmips_asc.c new file mode 100644 index 0000000000..b191241dbf --- /dev/null +++ b/target/linux/ifxmips/files/drivers/serial/ifxmips_asc.c @@ -0,0 +1,608 @@ +/* + * Driver for IFXMIPSASC serial ports + * + * Based on drivers/char/serial.c, by Linus Torvalds, Theodore Ts'o. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * Copyright (C) 2004 Infineon IFAP DC COM CPE + * Copyright (C) 2007 Felix Fietkau + * Copyright (C) 2007 John Crispin + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define PORT_IFXMIPSASC 111 + +#include + +#define UART_DUMMY_UER_RX 1 + +static void ifxmipsasc_tx_chars(struct uart_port *port); +extern void prom_printf(const char * fmt, ...); +static struct uart_port ifxmipsasc_port; +static struct uart_driver ifxmipsasc_reg; +static unsigned int uartclk = 0; +extern unsigned int ifxmips_get_fpi_hz(void); + +static void +ifxmipsasc_stop_tx (struct uart_port *port) +{ + /* fifo underrun shuts up after firing once */ + return; +} + +static void +ifxmipsasc_start_tx (struct uart_port *port) +{ + unsigned long flags; + + local_irq_save(flags); + ifxmipsasc_tx_chars(port); + local_irq_restore(flags); + + return; +} + +static void +ifxmipsasc_stop_rx (struct uart_port *port) +{ + /* clear the RX enable bit */ + writel(ASCWHBSTATE_CLRREN, IFXMIPS_ASC1_WHBSTATE); +} + +static void +ifxmipsasc_enable_ms (struct uart_port *port) +{ + /* no modem signals */ + return; +} + +static void +ifxmipsasc_rx_chars (struct uart_port *port) +{ + struct tty_struct *tty = port->info->tty; + unsigned int ch = 0, rsr = 0, fifocnt; + + fifocnt = readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_RXFFLMASK; + while (fifocnt--) + { + u8 flag = TTY_NORMAL; + ch = readl(IFXMIPS_ASC1_RBUF); + rsr = (readl(IFXMIPS_ASC1_STATE) & ASCSTATE_ANY) | UART_DUMMY_UER_RX; + tty_flip_buffer_push(tty); + port->icount.rx++; + + /* + * Note that the error handling code is + * out of the main execution path + */ + if (rsr & ASCSTATE_ANY) { + if (rsr & ASCSTATE_PE) { + port->icount.parity++; + writel(readl(IFXMIPS_ASC1_WHBSTATE) | ASCWHBSTATE_CLRPE, IFXMIPS_ASC1_WHBSTATE); + } else if (rsr & ASCSTATE_FE) { + port->icount.frame++; + writel(readl(IFXMIPS_ASC1_WHBSTATE) | ASCWHBSTATE_CLRFE, IFXMIPS_ASC1_WHBSTATE); + } + if (rsr & ASCSTATE_ROE) { + port->icount.overrun++; + writel(readl(IFXMIPS_ASC1_WHBSTATE) | ASCWHBSTATE_CLRROE, IFXMIPS_ASC1_WHBSTATE); + } + + rsr &= port->read_status_mask; + + if (rsr & ASCSTATE_PE) + flag = TTY_PARITY; + else if (rsr & ASCSTATE_FE) + flag = TTY_FRAME; + } + + if ((rsr & port->ignore_status_mask) == 0) + tty_insert_flip_char(tty, ch, flag); + + if (rsr & ASCSTATE_ROE) + /* + * Overrun is special, since it's reported + * immediately, and doesn't affect the current + * character + */ + tty_insert_flip_char(tty, 0, TTY_OVERRUN); + } + if (ch != 0) + tty_flip_buffer_push(tty); + + return; +} + + +static void +ifxmipsasc_tx_chars (struct uart_port *port) +{ + struct circ_buf *xmit = &port->info->xmit; + + if (uart_tx_stopped(port)) { + ifxmipsasc_stop_tx(port); + return; + } + + while(((readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_TXFFLMASK) + >> ASCFSTAT_TXFFLOFF) != IFXMIPSASC_TXFIFO_FULL) + { + if (port->x_char) { + writel(port->x_char, IFXMIPS_ASC1_TBUF); + port->icount.tx++; + port->x_char = 0; + continue; + } + + if (uart_circ_empty(xmit)) + break; + + writel(port->info->xmit.buf[port->info->xmit.tail], IFXMIPS_ASC1_TBUF); + xmit->tail = (xmit->tail + 1) & (UART_XMIT_SIZE - 1); + port->icount.tx++; + } + + if (uart_circ_chars_pending(xmit) < WAKEUP_CHARS) + uart_write_wakeup(port); +} + +static irqreturn_t +ifxmipsasc_tx_int (int irq, void *port) +{ + writel(ASC_IRNCR_TIR, IFXMIPS_ASC1_IRNCR); + ifxmipsasc_start_tx(port); + mask_and_ack_ifxmips_irq(irq); + + return IRQ_HANDLED; +} + +static irqreturn_t +ifxmipsasc_er_int (int irq, void *port) +{ + /* clear any pending interrupts */ + writel(readl(IFXMIPS_ASC1_WHBSTATE) | ASCWHBSTATE_CLRPE | + ASCWHBSTATE_CLRFE | ASCWHBSTATE_CLRROE, IFXMIPS_ASC1_WHBSTATE); + + return IRQ_HANDLED; +} + +static irqreturn_t +ifxmipsasc_rx_int (int irq, void *port) +{ + writel(ASC_IRNCR_RIR, IFXMIPS_ASC1_IRNCR); + ifxmipsasc_rx_chars((struct uart_port *) port); + mask_and_ack_ifxmips_irq(irq); + + return IRQ_HANDLED; +} + +static unsigned int +ifxmipsasc_tx_empty (struct uart_port *port) +{ + int status; + + status = readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_TXFFLMASK; + + return status ? 0 : TIOCSER_TEMT; +} + +static unsigned int +ifxmipsasc_get_mctrl (struct uart_port *port) +{ + return TIOCM_CTS | TIOCM_CAR | TIOCM_DSR; +} + +static void +ifxmipsasc_set_mctrl (struct uart_port *port, u_int mctrl) +{ + return; +} + +static void +ifxmipsasc_break_ctl (struct uart_port *port, int break_state) +{ + return; +} + +static void +ifxmipsasc1_hw_init (void) +{ + /* this setup was probably already done in ROM/u-boot but we do it again*/ + /* TODO: GPIO pins are multifunction */ + writel(readl(IFXMIPS_ASC1_CLC) & ~IFXMIPS_ASC1_CLC_DISS, IFXMIPS_ASC1_CLC); + writel((readl(IFXMIPS_ASC1_CLC) & ~ASCCLC_RMCMASK) | (1 << ASCCLC_RMCOFFSET), IFXMIPS_ASC1_CLC); + writel(0, IFXMIPS_ASC1_PISEL); + writel(((IFXMIPSASC_TXFIFO_FL << ASCTXFCON_TXFITLOFF) & + ASCTXFCON_TXFITLMASK) | ASCTXFCON_TXFEN | ASCTXFCON_TXFFLU, IFXMIPS_ASC1_TXFCON); + writel(((IFXMIPSASC_RXFIFO_FL << ASCRXFCON_RXFITLOFF) & + ASCRXFCON_RXFITLMASK) | ASCRXFCON_RXFEN | ASCRXFCON_RXFFLU, IFXMIPS_ASC1_RXFCON); + wmb (); + + /*framing, overrun, enable */ + writel(readl(IFXMIPS_ASC1_CON) | ASCCON_M_8ASYNC | ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN, + IFXMIPS_ASC1_CON); +} + +static int +ifxmipsasc_startup (struct uart_port *port) +{ + unsigned long flags; + int retval; + + /* this assumes: CON.BRS = CON.FDE = 0 */ + if (uartclk == 0) + uartclk = ifxmips_get_fpi_hz(); + + ifxmipsasc_port.uartclk = uartclk; + + ifxmipsasc1_hw_init(); + + local_irq_save(flags); + + retval = request_irq(IFXMIPSASC1_RIR, ifxmipsasc_rx_int, IRQF_DISABLED, "asc_rx", port); + if (retval){ + printk("failed to request ifxmipsasc_rx_int\n"); + return retval; + } + + retval = request_irq(IFXMIPSASC1_TIR, ifxmipsasc_tx_int, IRQF_DISABLED, "asc_tx", port); + if (retval){ + printk("failed to request ifxmipsasc_tx_int\n"); + goto err1; + } + + retval = request_irq(IFXMIPSASC1_EIR, ifxmipsasc_er_int, IRQF_DISABLED, "asc_er", port); + if (retval){ + printk("failed to request ifxmipsasc_er_int\n"); + goto err2; + } + + writel(ASC_IRNREN_RX_BUF | ASC_IRNREN_TX_BUF | ASC_IRNREN_ERR | ASC_IRNREN_TX, + IFXMIPS_ASC1_IRNREN); + + local_irq_restore(flags); + + return 0; + +err2: + free_irq(IFXMIPSASC1_TIR, port); + +err1: + free_irq(IFXMIPSASC1_RIR, port); + local_irq_restore(flags); + + return retval; +} + +static void +ifxmipsasc_shutdown (struct uart_port *port) +{ + free_irq(IFXMIPSASC1_RIR, port); + free_irq(IFXMIPSASC1_TIR, port); + free_irq(IFXMIPSASC1_EIR, port); + /* + * disable the baudrate generator to disable the ASC + */ + writel(0, IFXMIPS_ASC1_CON); + + /* flush and then disable the fifos */ + writel(readl(IFXMIPS_ASC1_RXFCON) | ASCRXFCON_RXFFLU, IFXMIPS_ASC1_RXFCON); + writel(readl(IFXMIPS_ASC1_RXFCON) & ~ASCRXFCON_RXFEN, IFXMIPS_ASC1_RXFCON); + writel(readl(IFXMIPS_ASC1_TXFCON) | ASCTXFCON_TXFFLU, IFXMIPS_ASC1_TXFCON); + writel(readl(IFXMIPS_ASC1_TXFCON) & ~ASCTXFCON_TXFEN, IFXMIPS_ASC1_TXFCON); +} + +static void ifxmipsasc_set_termios(struct uart_port *port, struct ktermios *new, struct ktermios *old) +{ + unsigned int cflag; + unsigned int iflag; + unsigned int quot; + unsigned int baud; + unsigned int con = 0; + unsigned long flags; + + cflag = new->c_cflag; + iflag = new->c_iflag; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS7: + con = ASCCON_M_7ASYNC; + break; + + case CS5: + case CS6: + default: + con = ASCCON_M_8ASYNC; + break; + } + + if (cflag & CSTOPB) + con |= ASCCON_STP; + + if (cflag & PARENB) { + if (!(cflag & PARODD)) + con &= ~ASCCON_ODD; + else + con |= ASCCON_ODD; + } + + port->read_status_mask = ASCSTATE_ROE; + if (iflag & INPCK) + port->read_status_mask |= ASCSTATE_FE | ASCSTATE_PE; + + port->ignore_status_mask = 0; + if (iflag & IGNPAR) + port->ignore_status_mask |= ASCSTATE_FE | ASCSTATE_PE; + + if (iflag & IGNBRK) { + /* + * If we're ignoring parity and break indicators, + * ignore overruns too (for real raw support). + */ + if (iflag & IGNPAR) + port->ignore_status_mask |= ASCSTATE_ROE; + } + + if ((cflag & CREAD) == 0) + port->ignore_status_mask |= UART_DUMMY_UER_RX; + + /* set error signals - framing, parity and overrun, enable receiver */ + con |= ASCCON_FEN | ASCCON_TOEN | ASCCON_ROEN; + + local_irq_save(flags); + + /* set up CON */ + writel(readl(IFXMIPS_ASC1_CON) | con, IFXMIPS_ASC1_CON); + + /* Set baud rate - take a divider of 2 into account */ + baud = uart_get_baud_rate(port, new, old, 0, port->uartclk / 16); + quot = uart_get_divisor(port, baud); + quot = quot / 2 - 1; + + /* disable the baudrate generator */ + writel(readl(IFXMIPS_ASC1_CON) & ~ASCCON_R, IFXMIPS_ASC1_CON); + + /* make sure the fractional divider is off */ + writel(readl(IFXMIPS_ASC1_CON) & ~ASCCON_FDE, IFXMIPS_ASC1_CON); + + /* set up to use divisor of 2 */ + writel(readl(IFXMIPS_ASC1_CON) & ~ASCCON_BRS, IFXMIPS_ASC1_CON); + + /* now we can write the new baudrate into the register */ + writel(quot, IFXMIPS_ASC1_BG); + + /* turn the baudrate generator back on */ + writel(readl(IFXMIPS_ASC1_CON) | ASCCON_R, IFXMIPS_ASC1_CON); + + /* enable rx */ + writel(ASCWHBSTATE_SETREN, IFXMIPS_ASC1_WHBSTATE); + + local_irq_restore(flags); +} + +static const char* +ifxmipsasc_type (struct uart_port *port) +{ + return port->type == PORT_IFXMIPSASC ? "IFXMIPSASC" : NULL; +} + +static void +ifxmipsasc_release_port (struct uart_port *port) +{ + return; +} + +static int +ifxmipsasc_request_port (struct uart_port *port) +{ + return 0; +} + +static void +ifxmipsasc_config_port (struct uart_port *port, int flags) +{ + if (flags & UART_CONFIG_TYPE) { + port->type = PORT_IFXMIPSASC; + ifxmipsasc_request_port(port); + } +} + +static int +ifxmipsasc_verify_port (struct uart_port *port, struct serial_struct *ser) +{ + int ret = 0; + if (ser->type != PORT_UNKNOWN && ser->type != PORT_IFXMIPSASC) + ret = -EINVAL; + if (ser->irq < 0 || ser->irq >= NR_IRQS) + ret = -EINVAL; + if (ser->baud_base < 9600) + ret = -EINVAL; + return ret; +} + +static struct uart_ops ifxmipsasc_pops = { + .tx_empty = ifxmipsasc_tx_empty, + .set_mctrl = ifxmipsasc_set_mctrl, + .get_mctrl = ifxmipsasc_get_mctrl, + .stop_tx = ifxmipsasc_stop_tx, + .start_tx = ifxmipsasc_start_tx, + .stop_rx = ifxmipsasc_stop_rx, + .enable_ms = ifxmipsasc_enable_ms, + .break_ctl = ifxmipsasc_break_ctl, + .startup = ifxmipsasc_startup, + .shutdown = ifxmipsasc_shutdown, + .set_termios = ifxmipsasc_set_termios, + .type = ifxmipsasc_type, + .release_port = ifxmipsasc_release_port, + .request_port = ifxmipsasc_request_port, + .config_port = ifxmipsasc_config_port, + .verify_port = ifxmipsasc_verify_port, +}; + +static struct uart_port ifxmipsasc_port = { + membase: (void *)IFXMIPS_ASC1_BASE_ADDR, + mapbase: IFXMIPS_ASC1_BASE_ADDR, + iotype: SERIAL_IO_MEM, + irq: IFXMIPSASC1_RIR, + uartclk: 0, + fifosize: 16, + unused: {IFXMIPSASC1_TIR, IFXMIPSASC1_EIR}, + type: PORT_IFXMIPSASC, + ops: &ifxmipsasc_pops, + flags: ASYNC_BOOT_AUTOCONF, +}; + +static void +ifxmipsasc_console_write (struct console *co, const char *s, u_int count) +{ + int i, fifocnt; + unsigned long flags; + + local_irq_save(flags); + for (i = 0; i < count; i++) + { + /* wait until the FIFO is not full */ + do + { + fifocnt = (readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_TXFFLMASK) + >> ASCFSTAT_TXFFLOFF; + } while (fifocnt == IFXMIPSASC_TXFIFO_FULL); + + if (s[i] == '\0') + { + break; + } + + if (s[i] == '\n') + { + writel('\r', IFXMIPS_ASC1_TBUF); + do + { + fifocnt = (readl(IFXMIPS_ASC1_FSTAT) & ASCFSTAT_TXFFLMASK) + >> ASCFSTAT_TXFFLOFF; + } while (fifocnt == IFXMIPSASC_TXFIFO_FULL); + } + writel(s[i], IFXMIPS_ASC1_TBUF); + } + + local_irq_restore(flags); +} + +static int __init +ifxmipsasc_console_setup (struct console *co, char *options) +{ + struct uart_port *port; + int baud = 115200; + int bits = 8; + int parity = 'n'; + int flow = 'n'; + + if (uartclk == 0) + uartclk = ifxmips_get_fpi_hz(); + co->index = 0; + port = &ifxmipsasc_port; + ifxmipsasc_port.uartclk = uartclk; + ifxmipsasc_port.type = PORT_IFXMIPSASC; + + if (options){ + uart_parse_options(options, &baud, &parity, &bits, &flow); + } + + return uart_set_options(port, co, baud, parity, bits, flow); +} + +static struct uart_driver ifxmipsasc_reg; +static struct console ifxmipsasc_console = { + name: "ttyS", + write: ifxmipsasc_console_write, + device: uart_console_device, + setup: ifxmipsasc_console_setup, + flags: CON_PRINTBUFFER, + index: -1, + data: &ifxmipsasc_reg, +}; + +static int __init +ifxmipsasc_console_init (void) +{ + register_console(&ifxmipsasc_console); + return 0; +} +console_initcall(ifxmipsasc_console_init); + +static struct uart_driver ifxmipsasc_reg = { + .owner = THIS_MODULE, + .driver_name = "serial", + .dev_name = "ttyS", + .major = TTY_MAJOR, + .minor = 64, + .nr = 1, + .cons = &ifxmipsasc_console, +}; + +static int __init +ifxmipsasc_init (void) +{ + unsigned char res; + + uart_register_driver(&ifxmipsasc_reg); + res = uart_add_one_port(&ifxmipsasc_reg, &ifxmipsasc_port); + + return res; +} + +static void __exit +ifxmipsasc_exit (void) +{ + uart_unregister_driver(&ifxmipsasc_reg); +} + +module_init(ifxmipsasc_init); +module_exit(ifxmipsasc_exit); + +MODULE_AUTHOR("John Crispin "); +MODULE_DESCRIPTION("MIPS IFXMips serial port driver"); +MODULE_LICENSE("GPL");