#define CONFIG_MIPS_IKAN /*-----------------------------------------------------------------------------------------------*\ \*-----------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /*--- #define AR7GPIO_DEBUG ---*/ #undef AR7GPIO_DEBUG #if defined(AR7GPIO_DEBUG) #define DBG(...) printk(KERN_INFO __VA_ARGS__) #else /*--- #if defined(AR7GPIO_DEBUG) ---*/ #define DBG(...) #endif /*--- #else ---*/ /*--- #if defined(AR7GPIO_DEBUG) ---*/ #if defined (CONFIG_MACH_FUSIV) static spinlock_t ikan_gpio_spinlock; struct ikanos_gpio_config g_gpio_cfg[GPIO_COUNT]; unsigned int g_gpio_cnt = 0; /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void ikan_gpio_dump_registers(void) { } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void reset_registers(void) { IKS_REG_W32(0, VX185_GPIO_ALTFUNC_SEL); IKS_REG_W32(0, VX185_GPIO_ALTFUNC_VAL); IKS_REG_W32(0xffffffff, VX185_GPIO_OUTPUT_CLEAR); IKS_REG_W32(0, VX185_GPIO_MODE1); IKS_REG_W32(0, VX185_GPIO_MODE2); } #if defined(AR7GPIO_DEBUG) /*--------------------------------------------------------------------------------*\ \*--------------------------------------------------------------------------------*/ static void gpiodump(unsigned int pin){ unsigned int mode; if(pin < 16){ mode = (IKS_REG_R32(VX185_GPIO_MODE1) >> (pin * 2) ) & 0x3; } else{ mode = (IKS_REG_R32(VX185_GPIO_MODE2) >> ((pin - 16) * 2)) & 0x3; } DBG("[GPIO]%s:%d: %s %s \n", __func__, pin, (IKS_REG_R32(VX185_GPIO_ALTFUNC_SEL) & ( 1 << pin)) ? "func" : "gpio", mode == 0 ? "in " : mode == 1 ? "out" : mode == 2 ? "od " : "os "); } #endif/*--- #if defined(AR7GPIO_DEBUG) ---*/ /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ static void set_gpio_mode(unsigned int pin, enum _hw_gpio_mode mode, enum _hw_gpio_direction dir, enum _hw_gpio_function func) { uint32_t mode_reg, val; pr_err("[%s] pin: %d mode: %d dir: %d func: %d\n", __func__, pin, mode, dir, func); if((pin >= GPIO_COUNT) || (mode > GPIO_MODE_LAST)){ pr_info("[GPIO] %s(%d,%d) invalid param\n", __func__, pin, mode); return; } if(dir == GPIO_INPUT_PIN && mode != GPIO_MODE_INPUT){ pr_warn("[%s] invalid configuration for pin %d: " "input direction and output mode %d requested\n", __func__, pin, mode); return; } // set or clear alternate function for pin val = IKS_REG_R32(VX185_GPIO_ALTFUNC_SEL); if(func == GPIO_PIN){ val &= ~(1 << pin); }else{ val |= (1 << pin); } IKS_REG_W32(val, VX185_GPIO_ALTFUNC_SEL); // pin mode is split into two registers if(pin < 16){ mode_reg = VX185_GPIO_MODE1; }else{ mode_reg = VX185_GPIO_MODE2; pin -= 16; } val = IKS_REG_R32(mode_reg); val &= ~(GPIO_MODE_VAL(pin, GPIO_MODE_MASK)); val |= GPIO_MODE_VAL(pin, mode); IKS_REG_W32(val, mode_reg); } struct _avm_hw_config *avm_get_hw_config_table(void); int init_gpio_config(void) { uint32_t i; struct _avm_hw_config *hw_cfg; hw_cfg = avm_get_hw_config_table(); if(hw_cfg == NULL){ pr_err("[%s] avm_current_hw_config not set!\n", __func__); return -ENOENT; } /*--- Reset GPIO functions: ---*/ reset_registers(); /*--- Set GPIO functions according to hardware config: ---*/ while(hw_cfg->name != NULL){ i = hw_cfg->value; if(i < ARRAY_SIZE(g_gpio_cfg)){ g_gpio_cfg[i].mode = hw_cfg->manufactor_hw_config.manufactor_ikanos_gpio_config.mode; g_gpio_cfg[i].dir = hw_cfg->manufactor_hw_config.manufactor_ikanos_gpio_config.dir; g_gpio_cfg[i].func_sel = hw_cfg->manufactor_hw_config.manufactor_ikanos_gpio_config.func_sel; g_gpio_cfg[i].func_val = hw_cfg->manufactor_hw_config.manufactor_ikanos_gpio_config.func_val; g_gpio_cfg[i].valid = 1; set_gpio_mode(i, g_gpio_cfg[i].mode, g_gpio_cfg[i].dir, g_gpio_cfg[i].func_sel ? FUNCTION_PIN : GPIO_PIN ); } else { pr_err("[%s] GPIO %d out of bounds. Check hw_config!\n", __func__, i); } ++hw_cfg; } return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ikan_gpio_init(void) { pr_info("[%s]\n", __func__); spin_lock_init(&ikan_gpio_spinlock); init_gpio_config(); return 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ikan_gpio_ctrl(unsigned int pin, enum _hw_gpio_function func, enum _hw_gpio_direction dir) { unsigned long flags; enum _hw_gpio_mode mode; /*--- printk(KERN_INFO"[GPIO] %s: pin %d is %s %s\n" , __func__, gpio_pin, pin_mode == GPIO_PIN ? "gpio" : "func", pin_dir == GPIO_OUTPUT_PIN ? "output" : "input"); ---*/ if(pin > GPIO_COUNT){ pr_err("[GPIO] invalid gpio pin %d\n", pin); return (-EINVAL); } spin_lock_irqsave(&ikan_gpio_spinlock, flags); // TKL: FIXME should we try to keep original output mode (OD, OS) instead // of just setting push/pull? mode = (dir == GPIO_OUTPUT_PIN) ? GPIO_MODE_OUTPUT : GPIO_MODE_INPUT; set_gpio_mode(pin, mode, dir, func); spin_unlock_irqrestore(&ikan_gpio_spinlock, flags); return (0); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ikan_read_irq_gpio(struct _hw_gpio_irqhandle *handle, unsigned int gpio_pin, unsigned int mask) { pr_err("[%s] IRQ mode not supported.\n", __func__); return -ENOTSUPP; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ struct _hw_gpio_irqhandle *ikan_gpio_request_irq(unsigned int mask, enum _hw_gpio_polarity mode, enum _hw_gpio_sensitivity edge, int (*handle_func)(unsigned int)) { pr_err("[%s] IRQ mode not supported.\n", __func__); return NULL; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void ikan_gpio_set_delayed_irq_mode(struct _hw_gpio_irqhandle *handle, int delayed) { pr_err("[%s] IRQ mode not supported.\n", __func__); return; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ikan_gpio_enable_irq(struct _hw_gpio_irqhandle *handle) { pr_err("[GPIO]%s: IRQ mode not supported.\n", __func__); return -ENOTSUPP; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ikan_gpio_disable_irq(struct _hw_gpio_irqhandle *handle) { pr_err("[GPIO]%s: IRQ mode not supported.\n", __func__); return -ENOTSUPP; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ikan_gpio_out_bit(unsigned int gpio_pin, int value) { unsigned long flags; if(gpio_pin >= GPIO_COUNT){ pr_err("[GPIO] invalid gpio pin %d\n", gpio_pin); return (-EINVAL); } spin_lock_irqsave(&ikan_gpio_spinlock, flags); if(value){ IKS_REG_W32((1 << gpio_pin), VX185_GPIO_OUTPUT_SET); }else{ IKS_REG_W32((1 << gpio_pin), VX185_GPIO_OUTPUT_CLEAR); } DBG("[GPIO]%s pin %d -> %d\n", __FUNCTION__, gpio_pin, value); /*--- gpiodump(gpio_pin); ---*/ spin_unlock_irqrestore(&ikan_gpio_spinlock, flags); return (0); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ int ikan_gpio_in_bit(unsigned int gpio_pin) { if(gpio_pin >= GPIO_COUNT){ pr_err("[GPIO] invalid gpio pin %d\n", gpio_pin); return (-1); } return (IKS_REG_R32(VX185_GPIO_INPUT) & (1 << gpio_pin)) ? 1 : 0; } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ unsigned int ikan_gpio_in_value(void) { return IKS_REG_R32(VX185_GPIO_INPUT); } /*------------------------------------------------------------------------------------------*\ \*------------------------------------------------------------------------------------------*/ void ikan_gpio_set_bitmask(unsigned int mask, unsigned int value) { unsigned long flags; spin_lock_irqsave(&ikan_gpio_spinlock, flags); IKS_REG_W32((value & mask), VX185_GPIO_OUTPUT_SET); IKS_REG_W32((~value & mask), VX185_GPIO_OUTPUT_CLEAR); spin_unlock_irqrestore(&ikan_gpio_spinlock, flags); } EXPORT_SYMBOL(ikan_gpio_init); EXPORT_SYMBOL(ikan_gpio_ctrl); EXPORT_SYMBOL(ikan_gpio_request_irq); EXPORT_SYMBOL(ikan_gpio_set_delayed_irq_mode); EXPORT_SYMBOL(ikan_gpio_enable_irq); EXPORT_SYMBOL(ikan_gpio_disable_irq); EXPORT_SYMBOL(ikan_read_irq_gpio); EXPORT_SYMBOL(ikan_gpio_out_bit); EXPORT_SYMBOL(ikan_gpio_in_bit); EXPORT_SYMBOL(ikan_gpio_in_value); EXPORT_SYMBOL(ikan_gpio_set_bitmask); #endif /*--- #if defined (CONFIG_MIPS_IKAN) ---*/