#ifndef EXPORT_SYMTAB #define EXPORT_SYMTAB #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct _hw_gpio_irqhandle *ath_avm_gpio_first_handle; #if defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) static struct _gpio_function *current_gpio_table; static unsigned int current_gpio_table_size; #endif unsigned int ath_gpio_int_both_edge; unsigned int ath_gpio_int_active_low; unsigned int ath_gpio_shiftreg_size; #if defined(CONFIG_SOC_QCN550X) unsigned int ath_gpio_shiftreg_rclk_pin = -1; #endif unsigned int ath_gpio_shiftreg_clk_pin = -1; unsigned int ath_gpio_shiftreg_din_pin = -1; void avmnet_gpio(unsigned int gpio, unsigned int on) __attribute__ ((weak)); void ath_avm_gpio_dump_registers(const char *prefix); static struct _avm_hw_config *get_gpio_config(const unsigned int gpio_num) { struct _avm_hw_config *config; config = avm_get_hw_config_table(); if (!config) return 0; /* error: no hardware config found! */ while (config->name) { if (gpio_num == config->value) return config; config++; } return 0; } static unsigned int get_gpio_invert(const unsigned int gpio_num) { struct _avm_hw_config *config; config = get_gpio_config(gpio_num); if (!config) return 0; /* error: no hardware config found! */ return (config->param == AVM_DEF_HW_PARAM_GPIO_OUT_ACTIVE_LOW || config->param == AVM_DEF_HW_PARAM_GPIO_IN_ACTIVE_LOW); } /* * LOW LEVEL GPIO ACCESS FUNCTIONS */ void ath_gpio_config_output(int gpio) { if (soc_is_ar934x() || soc_is_qca953x() || soc_is_qca955x() || soc_is_qca956x() || soc_is_qcn550x()) ath_reg_rmw_clear(ATH_GPIO_OE, (1 << gpio)); else ath_reg_rmw_set(ATH_GPIO_OE, (1 << gpio)); } void ath_gpio_config_input(int gpio) { if (soc_is_ar934x() || soc_is_qca953x() || soc_is_qca955x() || soc_is_qca956x() || soc_is_qcn550x()) ath_reg_rmw_set(ATH_GPIO_OE, (1 << gpio)); else ath_reg_rmw_clear(ATH_GPIO_OE, (1 << gpio)); } void ath_avm_gpio_set_polarity(unsigned int gpio, unsigned int pol) { if (pol) { ath_reg_rmw_set(ATH_GPIO_INT_POLARITY, (1 << gpio)); } else { ath_reg_rmw_clear(ATH_GPIO_INT_POLARITY, (1 << gpio)); } } EXPORT_SYMBOL(ath_avm_gpio_set_polarity); #define gpio_ath_reg_wr(_phys, _val) ((*(volatile ath_reg_t *)KSEG1ADDR(_phys)) = (_val)) static inline void ath_gpio_out_val(int gpio, int val) { if (get_gpio_invert(gpio)) val = !val; if (val) { gpio_ath_reg_wr(ATH_GPIO_SET, (1 << gpio)); } else { gpio_ath_reg_wr(ATH_GPIO_CLEAR, (1 << gpio)); } wmb(); } static inline int ath_gpio_in_val(int gpio) { return (1 << gpio) & (ath_reg_rd(ATH_GPIO_IN) ^ ath_gpio_int_active_low); } static void ath_gpio_intr_enable(struct irq_data *data) { ath_reg_rmw_set(ATH_GPIO_INT_MASK, (1 << (data->irq - ATH79_GPIO_IRQ_BASE))); irqd_irq_masked(data); } static void ath_gpio_intr_unmask(struct irq_data *data) { ath_reg_rmw_set(ATH_GPIO_INT_MASK, (1 << (data->irq - ATH79_GPIO_IRQ_BASE))); } static void ath_gpio_intr_mask(struct irq_data *data) { ath_reg_rmw_clear(ATH_GPIO_INT_MASK, (1 << (data->irq - ATH79_GPIO_IRQ_BASE))); } static void ath_gpio_intr_disable(struct irq_data *data) { ath_reg_rmw_clear(ATH_GPIO_INT_MASK, (1 << (data->irq - ATH79_GPIO_IRQ_BASE))); } static unsigned int ath_gpio_intr_startup(struct irq_data *data) { ath_reg_rmw_set(ATH_GPIO_INT_ENABLE, (1 << (data->irq - ATH79_GPIO_IRQ_BASE))); ath_gpio_intr_enable(data); return 0; } static void ath_gpio_intr_shutdown(struct irq_data *data) { ath_gpio_intr_disable(data); } static void ath_gpio_intr_ack(struct irq_data *data) { unsigned int gpio_bit = (1 << (data->irq - ATH79_GPIO_IRQ_BASE)); if (unlikely(ath_gpio_int_both_edge & gpio_bit)) { ath_reg_wr(ATH_GPIO_INT_POLARITY, ath_reg_rd(ATH_GPIO_INT_POLARITY) ^ gpio_bit); ath_reg_rd(ATH_GPIO_INT_POLARITY); } } static void ath_gpio_intr_end(struct irq_data *data) { if (!(irqd_irq_disabled(data) || irqd_irq_inprogress(data))) ath_gpio_intr_enable(data); } static int ath_gpio_intr_set_type(struct irq_data *data, unsigned int flow_type) { unsigned int gpio_bit; struct irq_desc *desc = &irq_desc[data->irq]; unsigned int irq = data->irq; gpio_bit = 1 << (irq - ATH79_GPIO_IRQ_BASE); /*--- pr_err("[%s]: irq %d trigger type %d\n", __func__, irq, flow_type); ---*/ switch (flow_type) { case IRQF_TRIGGER_NONE: pr_err("[%s %d]: Assuming IRQ%d level triggered are already configured!\n", __func__, __LINE__, irq); ath_gpio_int_both_edge &= ~gpio_bit; desc->handle_irq = handle_level_irq; break; case IRQF_TRIGGER_RISING: /* edge triggered & active high */ ath_gpio_int_both_edge &= ~gpio_bit; ath_reg_rmw_clear(ATH_GPIO_INT_TYPE, gpio_bit); ath_reg_rmw_set(ATH_GPIO_INT_POLARITY, gpio_bit); desc->handle_irq = handle_edge_irq; break; case IRQF_TRIGGER_FALLING: /* edge triggered & active low */ ath_gpio_int_both_edge &= ~gpio_bit; ath_reg_rmw_clear(ATH_GPIO_INT_TYPE, gpio_bit); ath_reg_rmw_clear(ATH_GPIO_INT_POLARITY, gpio_bit); desc->handle_irq = handle_edge_irq; break; case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_HIGH: /* both edge triggered & active high (emuliert, initial wie IRQF_TRIGGER_RISING) */ ath_gpio_int_both_edge |= gpio_bit; ath_gpio_int_active_low &= ~gpio_bit; /*--- pr_err("[%s] IRQF_TRIGGER_HIGH gpio_bit=0x%x both_edge=0x%x", __func__, gpio_bit, ath_gpio_int_both_edge); ---*/ ath_reg_rmw_clear(ATH_GPIO_INT_TYPE, gpio_bit); ath_reg_rmw_set(ATH_GPIO_INT_POLARITY, gpio_bit); desc->handle_irq = handle_edge_irq; break; case IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_TRIGGER_LOW: /* both edge triggered & active high (emuliert, initial wie IRQF_TRIGGER_FALLING) */ ath_gpio_int_both_edge |= gpio_bit; ath_gpio_int_active_low |= gpio_bit; /*--- pr_err("[%s] IRQF_TRIGGER_LOW gpio_bit=0x%x both_edge=0x%x", __func__, gpio_bit, ath_gpio_int_both_edge); ---*/ ath_reg_rmw_clear(ATH_GPIO_INT_TYPE, gpio_bit); ath_reg_rmw_clear(ATH_GPIO_INT_POLARITY, gpio_bit); desc->handle_irq = handle_edge_irq; break; case IRQF_TRIGGER_HIGH: /* level sensitive & active high */ ath_gpio_int_both_edge &= ~gpio_bit; ath_gpio_int_active_low &= ~gpio_bit; ath_reg_rmw_set(ATH_GPIO_INT_TYPE, gpio_bit); ath_reg_rmw_set(ATH_GPIO_INT_POLARITY, gpio_bit); desc->handle_irq = handle_level_irq; break; case IRQF_TRIGGER_LOW: /* level sensitive & active low */ ath_gpio_int_both_edge &= ~gpio_bit; ath_gpio_int_active_low |= gpio_bit; ath_reg_rmw_set(ATH_GPIO_INT_TYPE, gpio_bit); ath_reg_rmw_clear(ATH_GPIO_INT_POLARITY, gpio_bit); desc->handle_irq = handle_level_irq; break; default: pr_err("[%s %d]: Invalid irq %d trigger type %d\n", __func__, __LINE__, irq, flow_type); break; } return 0; } static struct irq_chip /* hw_interrupt_type */ ath_gpio_intr_controller = { .name = "GPIO", .irq_set_type = ath_gpio_intr_set_type, .irq_startup = ath_gpio_intr_startup, .irq_shutdown = ath_gpio_intr_shutdown, .irq_enable = ath_gpio_intr_enable, .irq_disable = ath_gpio_intr_disable, .irq_mask = ath_gpio_intr_mask, .irq_unmask = ath_gpio_intr_unmask, .irq_ack = ath_gpio_intr_ack, .irq_eoi = ath_gpio_intr_end, }; static void ath79_gpio_irq_handler(struct irq_desc *desc) { u32 pending; pending = ath_reg_rd(ATH_GPIO_INT_PENDING) & ath_reg_rd(ATH_GPIO_INT_MASK); if (!pending) { spurious_interrupt(); return; } desc->irq_data.chip->irq_ack(&desc->irq_data); while (pending) { int bit = __ffs(pending); generic_handle_irq(ATH79_GPIO_IRQ(bit)); pending &= ~BIT(bit); } } static int gpio_map(struct irq_domain *d, unsigned int irq, irq_hw_number_t hw) { irq_set_chip_and_handler(irq, &ath_gpio_intr_controller, handle_level_irq); return 0; } static const struct irq_domain_ops gpio_irq_domain_ops = { .xlate = irq_domain_xlate_onecell, .map = gpio_map, }; static int __init ath79_gpio_intc_of_init( struct device_node *node, struct device_node *parent) { struct irq_domain *domain; int irq; irq = irq_of_parse_and_map(node, 0); if (!irq) panic("Failed to get GPIO IRQ"); domain = irq_domain_add_legacy(node, ATH79_GPIO_IRQ_COUNT, ATH79_GPIO_IRQ_BASE, 0, &gpio_irq_domain_ops, NULL); if (!domain) panic("Failed to add GPIO irqdomain"); irq_set_chained_handler(irq, ath79_gpio_irq_handler); return 0; } IRQCHIP_DECLARE(ath79_gpio_intc, "qca,ath79-gpio-intc", ath79_gpio_intc_of_init); /* * AVM GPIO API */ void ath_avm_gpio_dump_registers(const char *prefix) { pr_err("[%s] GPIO register dump:\n", prefix ? prefix : ""); pr_err(" ATH_GPIO_OE(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_OE), ath_reg_rd(ATH_GPIO_OE)); pr_err(" ATH_GPIO_IN(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_IN), ath_reg_rd(ATH_GPIO_IN)); pr_err(" ATH_GPIO_OUT(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_OUT), ath_reg_rd(ATH_GPIO_OUT)); pr_err(" ATH_GPIO_INT_ENABLE(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_INT_ENABLE), ath_reg_rd(ATH_GPIO_INT_ENABLE)); pr_err(" ATH_GPIO_INT_TYPE(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_INT_TYPE), ath_reg_rd(ATH_GPIO_INT_TYPE)); pr_err(" ATH_GPIO_INT_POLARITY(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_INT_POLARITY), ath_reg_rd(ATH_GPIO_INT_POLARITY)); pr_err(" ATH_GPIO_INT_PENDING(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_INT_PENDING), ath_reg_rd(ATH_GPIO_INT_PENDING)); pr_err(" ATH_GPIO_INT_MASK(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_INT_MASK), ath_reg_rd(ATH_GPIO_INT_MASK)); #ifdef CONFIG_SOC_AR724X pr_err(" ATH_GPIO_FUNCTIONS(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_FUNCTIONS), ath_reg_rd(ATH_GPIO_FUNCTIONS)); pr_err(" ATH_GPIO_FUNCTION_2 = 0x%08x\n", ath_reg_rd(ATH_GPIO_FUNCTION_2)); #endif /*--- #ifdef CONFIG_SOC_AR724X ---*/ #if defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCN550X) pr_err(" ATH_GPIO_IN_ETH_SWITCH_LED(%08x)= 0x%08x\n", KSEG1ADDR(ATH_GPIO_IN_ETH_SWITCH_LED), ath_reg_rd(ATH_GPIO_IN_ETH_SWITCH_LED)); pr_err(" ATH_GPIO_OUT_FUNCTION0(%08x) = 0x%08x (gpio 0-3)\n", KSEG1ADDR(ATH_GPIO_OUT_FUNCTION0), ath_reg_rd(ATH_GPIO_OUT_FUNCTION0)); pr_err(" ATH_GPIO_OUT_FUNCTION1(%08x) = 0x%08x (gpio 4-7)\n", KSEG1ADDR(ATH_GPIO_OUT_FUNCTION1), ath_reg_rd(ATH_GPIO_OUT_FUNCTION1)); pr_err(" ATH_GPIO_OUT_FUNCTION2(%08x) = 0x%08x (gpio 8-11)\n", KSEG1ADDR(ATH_GPIO_OUT_FUNCTION2), ath_reg_rd(ATH_GPIO_OUT_FUNCTION2)); pr_err(" ATH_GPIO_OUT_FUNCTION3(%08x) = 0x%08x (gpio 12-15)\n", KSEG1ADDR(ATH_GPIO_OUT_FUNCTION3), ath_reg_rd(ATH_GPIO_OUT_FUNCTION3)); pr_err(" ATH_GPIO_OUT_FUNCTION4(%08x) = 0x%08x (gpio 16-19)\n", KSEG1ADDR(ATH_GPIO_OUT_FUNCTION4), ath_reg_rd(ATH_GPIO_OUT_FUNCTION4)); pr_err(" ATH_GPIO_OUT_FUNCTION5(%08x) = 0x%08x (gpio 20-23)\n", KSEG1ADDR(ATH_GPIO_OUT_FUNCTION5), ath_reg_rd(ATH_GPIO_OUT_FUNCTION5)); pr_err(" ATH_GPIO_IN_ENABLE0(%08x) = 0x%08x (UART0/SPI)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE0), ath_reg_rd(ATH_GPIO_IN_ENABLE0)); pr_err(" ATH_GPIO_IN_ENABLE1(%08x) = 0x%08x (I2S)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE1), ath_reg_rd(ATH_GPIO_IN_ENABLE1)); pr_err(" ATH_GPIO_IN_ENABLE2(%08x) = 0x%08x (ETHRX)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE2), ath_reg_rd(ATH_GPIO_IN_ENABLE2)); pr_err(" ATH_GPIO_IN_ENABLE3(%08x) = 0x%08x (MDIO)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE3), ath_reg_rd(ATH_GPIO_IN_ENABLE3)); pr_err(" ATH_GPIO_IN_ENABLE4(%08x) = 0x%08x (SLIC)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE4), ath_reg_rd(ATH_GPIO_IN_ENABLE4)); pr_err(" ATH_GPIO_IN_ENABLE5(%08x) = 0x%08x (I2C)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE5), ath_reg_rd(ATH_GPIO_IN_ENABLE5)); pr_err(" ATH_GPIO_IN_ENABLE6(%08x) = 0x%08x (?)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE6), ath_reg_rd(ATH_GPIO_IN_ENABLE6)); pr_err(" ATH_GPIO_IN_ENABLE7(%08x) = 0x%08x (?)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE7), ath_reg_rd(ATH_GPIO_IN_ENABLE7)); pr_err(" ATH_GPIO_IN_ENABLE8(%08x) = 0x%08x (?)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE8), ath_reg_rd(ATH_GPIO_IN_ENABLE8)); pr_err(" ATH_GPIO_IN_ENABLE9(%08x) = 0x%08x (UART1)\n", KSEG1ADDR(ATH_GPIO_IN_ENABLE9), ath_reg_rd(ATH_GPIO_IN_ENABLE9)); pr_err(" ATH_GPIO_FUNCTIONS(%08x) = 0x%08x\n", KSEG1ADDR(ATH_GPIO_FUNCTIONS), ath_reg_rd(ATH_GPIO_FUNCTIONS)); #endif } EXPORT_SYMBOL(ath_avm_gpio_dump_registers); #if defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA953X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) /* * mbahr: Doppelbelegung erlaubt ? * was sind ATH_GPIO_IN_ENABLE5 - ATH_GPIO_IN_ENABLE8 ?? */ static void ath_infunction_clear(unsigned int gpio_pin) { unsigned int inaddr, i; for (inaddr = ATH_GPIO_IN_ENABLE(0); inaddr <= ATH_GPIO_IN_ENABLE(9); inaddr += sizeof(unsigned int)) { unsigned int funcin_val; if ((inaddr >= ATH_GPIO_IN_ENABLE(4)) && (inaddr != ATH_GPIO_IN_ENABLE(9))) { /*--- undokumentiert ? ---*/ continue; } funcin_val = ath_reg_rd(inaddr); for (i = 0; i < 32; i += 8) { if (((funcin_val >> i) & 0xff) == gpio_pin) { /*--- pr_err("warning[%d]: %08x %08x contain gpio_pin %d\n", i, inaddr, funcin_val, gpio_pin); ---*/ funcin_val = (funcin_val & ~(0xff << i)); ath_reg_wr(inaddr, funcin_val); } } } } void __gpio_infunction_set(unsigned int gpio_pin, int func) { unsigned int val; #if 0 if (((func == GPIO_IN_SPI_MISO) || (func == GPIO_IN_UART0_SIN)) && (gpio_pin > 17)) { pr_err("[%s] error: invalid GPIO %d for input function %d (only gpio pin < 18 allowed)\n", __func__, gpio_pin, func); return; } #endif ath_infunction_clear(gpio_pin); if (func == NO_FUNCTION) { /*--- pr_err("[%s] Clear input function register for gpio %d\n", __func__, gpio_pin); ---*/ return; } val = ath_reg_rd(ATH_GPIO_IN_ENABLE_REG(func)); val = ATH_GPIO_IN_ENABLE_SET(val, func, gpio_pin); ath_reg_wr(ATH_GPIO_IN_ENABLE_REG(func), val); /*--- pr_err("[%s] Set input function register for gpio %u to func %d (reg=0x%x, val=0x%x)\n", __func__, ---*/ /*--- gpio_pin, func, GPIO_IN_ENABLE_REG(func), val); ---*/ } void __gpio_outfunction_set(unsigned int gpio_pin, int func) { unsigned int val; if (func == NO_FUNCTION) func = 0; val = ath_reg_rd(ATH_GPIO_OUT_FUNC_REG(gpio_pin)); val = ATH_GPIO_OUT_FUNC_SET(val, func, gpio_pin); ath_reg_wr(ATH_GPIO_OUT_FUNC_REG(gpio_pin), val); /*--- pr_err("[%s] Set output function register for gpio %u to func %d (reg=0x%x, val=0x%x)\n", __func__, ---*/ /*--- gpio_pin, func, GPIO_OUT_FUNC_REG(gpio_pin), val); ---*/ } static inline void ath_avm_gpio_infunction_set(unsigned int gpio_pin, int func) { __gpio_outfunction_set(gpio_pin, NO_FUNCTION); __gpio_infunction_set(gpio_pin, func); } static inline void ath_avm_gpio_outfunction_set(unsigned int gpio_pin, int func) { __gpio_infunction_set(gpio_pin, NO_FUNCTION); __gpio_outfunction_set(gpio_pin, func); } static inline void ath_avm_gpio_inoutfunction_set(unsigned int gpio_pin, int func) { __gpio_infunction_set(gpio_pin, func & 0xFFFF); __gpio_outfunction_set(gpio_pin, func >> 16); } #endif void ath_avm_gpio_init_functions(void) { unsigned int hwrev = 0, pin/*, i*/; char *s, *p; struct _avm_hw_config *config; s = prom_getenv("HWRevision"); if (s) { hwrev = simple_strtoul(s, &p, 10); } else { pr_err("[%s] error: no HWRevision detected in environment variables\n", __func__); BUG_ON(1); } config = avm_get_hw_config_table(); while (config->name) { if ((config->func == AVM_DEF_HW_FUNCTION_PIN_NOCHANGE) || (config->param == avm_hw_param_no_param)) { pr_debug("Ignoring GPIO %d (%s)\n", config->value, config->name); config++; continue; } pin = config->value; #if defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) if ((pin >= 14) && (pin <= 17)) #else if (pin < 4) #endif ath_reg_rmw_set(ATH_GPIO_FUNCTIONS, ATH_GPIO_FUNCTION_JTAG_DISABLE); switch (config->param) { case avm_hw_param_gpio_out_active_low: case avm_hw_param_gpio_out_active_high: #if defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA953X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) if (config->func == AVM_DEF_HW_FUNCTION_PIN_NOCHANGE) break; if (config->func == AVM_DEF_HW_FUNCTION_GPIO) { ath_avm_gpio_outfunction_set(pin, NO_FUNCTION); pr_debug("GPIO %d (%s) set to GPIO output\n", config->value, config->name); if (config->default_value != AVM_HW_DEFAULT_VALUE_UNDEF) { pr_debug("->Setting default value: %d\n", (uint32_t)(config->default_value)); ath_avm_gpio_out_bit(pin, (uint32_t) config->default_value); } } else { pr_debug("GPIO %d (%s) set to func output %08x\n", config->value, config->name, config->func); ath_avm_gpio_outfunction_set(pin, config->func); } #endif ath_gpio_config_output(pin); break; case avm_hw_param_gpio_in_active_low: case avm_hw_param_gpio_in_active_high: #if defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA953X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) if (config->func == AVM_DEF_HW_FUNCTION_PIN_NOCHANGE) break; if (config->func == AVM_DEF_HW_FUNCTION_GPIO) { pr_debug("GPIO %d (%s) set to GPIO input\n", config->value, config->name); ath_avm_gpio_infunction_set(pin, NO_FUNCTION); } else { pr_debug("GPIO %d (%s) set to func input %08x\n", config->value, config->name, config->func); ath_avm_gpio_infunction_set(pin, config->func); } #endif ath_gpio_config_input(pin); if (config->param == avm_hw_param_gpio_in_active_low) ath_gpio_int_active_low |= (1 << pin); break; case avm_hw_param_gpio_in_out_active_low: case avm_hw_param_gpio_in_out_active_high: #if defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA953X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) if (config->func == AVM_DEF_HW_FUNCTION_PIN_NOCHANGE) break; if (config->func == AVM_DEF_HW_FUNCTION_GPIO) { ath_avm_gpio_outfunction_set(pin, NO_FUNCTION); pr_debug("GPIO %d (%s) set to GPIO input/output\n", config->value, config->name); if (config->default_value != AVM_HW_DEFAULT_VALUE_UNDEF) { pr_debug("->Setting default value: %d\n", (uint32_t)(config->default_value)); ath_avm_gpio_out_bit(pin, (uint32_t) config->default_value); } } else { pr_debug("GPIO %d (%s) set to func input/output %08x\n", config->value, config->name, config->func); ath_avm_gpio_inoutfunction_set(pin, config->func); } #endif ath_gpio_config_output(pin); break; default: /* === Does not happen === */ break; }; config++; } } void ath_gpio_shift_register_load(unsigned int mask, unsigned int values) { unsigned int i, clk, din, dataout; static unsigned int ath_gpio_shiftreg_value; clk = 1 << ath_gpio_shiftreg_clk_pin; din = 1 << ath_gpio_shiftreg_din_pin; #if 0 pr_err("[%s] current=0x%x mask=0x%x values=0x%x new=0x%x\n", __func__, ath_gpio_shiftreg_value, mask, values, (ath_gpio_shiftreg_value & ~mask) | (mask & values)); #endif ath_gpio_shiftreg_value &= ~mask; ath_gpio_shiftreg_value |= mask & values; #ifndef CONFIG_SOC_QCN550X ath_gpio_shiftreg_value |= 1 << (ath_gpio_shiftreg_size - 1); /*--- muss zum Reset gesetzt sein ---*/ #endif for (i = ath_gpio_shiftreg_size; i; i--) { #if 0 pr_err("[%s] current=0x%x & 0x%x => 0x%x\n", __func__, ath_gpio_shiftreg_value, (1 << (i - 1)), (ath_gpio_shiftreg_value & (1 << (i - 1))) ? 1 : 0); #endif dataout = (ath_gpio_shiftreg_value & (1 << (i - 1))) ? 1 : 0; gpio_ath_reg_wr(ATH_GPIO_CLEAR, clk); if (dataout) gpio_ath_reg_wr(ATH_GPIO_SET, din); else gpio_ath_reg_wr(ATH_GPIO_CLEAR, din); gpio_ath_reg_wr(ATH_GPIO_SET, clk); udelay(1); wmb(); } #if defined(CONFIG_SOC_QCN550X) gpio_ath_reg_wr(ATH_GPIO_SET, 1 << ath_gpio_shiftreg_rclk_pin); udelay(1); gpio_ath_reg_wr(ATH_GPIO_CLEAR, 1 << ath_gpio_shiftreg_rclk_pin | clk | din); #else gpio_ath_reg_wr(ATH_GPIO_CLEAR, clk|din); #endif } int ath_gpio_setup_pin_mode(unsigned int gpio_pin, enum _hw_gpio_function pin_mode, enum _hw_gpio_direction pin_dir) { #if defined(CONFIG_SOC_AR724X) unsigned int bits = 0; unsigned int bits2 = 0; #elif defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) unsigned int function = NO_FUNCTION; #endif #if defined(CONFIG_SOC_AR724X) switch (gpio_pin) { case 0: /* SPI Chip select on GPIO_0 [Bit 13] */ bits |= ATH_GPIO_FUNCTION_SPI_CS_0_EN; /* Enables I2S_WS on GPIO_0 [FUNC_2 Bit 4] */ bits2 |= ATH_GPIO_FUNCTION_2_EN_I2WS_ON_0; break; case 1: /* SPI Chip select on GPIO_1 [Bit 14] */ bits |= ATH_GPIO_FUNCTION_SPI_CS_1_EN; /* Enables I2S_CK Out on GPIO_1 [FUNC_2 Bit 3] */ bits2 |= ATH_GPIO_FUNCTION_2_EN_I2SCK_ON_1; break; case 2: case 3: case 4: case 5: /* SPI Chip select on GPIO_2 - GPIO_5 [Bit 18] */ bits |= ATH_GPIO_FUNCTION_SPI_EN; break; case 6: case 7: case 8: /*--- case 11: ---*/ /*--- case 12: ---*/ /* I2S on GPIO_6-8 and 11-12 [Bit 26] */ bits |= ATH_GPIO_FUNCTION_I2S0_EN; break; case 9: case 10: /* Enables UART on GPIO_11 and GPIO_12 [Bit 1] */ bits |= ATH_GPIO_FUNCTION_UART_EN; break; case 11: if (pin_mode == GPIO_PIN) { /* Master Audio CLK_MCK on GPIO_11 (only if Bit 26 is set) [Bit 27] - clear only! */ bits |= ATH_GPIO_FUNCTION_I2S_MCKEN; /* Disable undocumented Function [Bit 20] (otherwise GPIO mode won't work) */ bits |= ATH_GPIO_FUNCTION_CLK_OBS6_ENABLE; } case 12: /* Enables UART RTS/CTS on GPIO_11 and GPIO_12 [Bit 2] - default */ bits |= ATH_GPIO_FUNCTION_UART_RTS_CTS_EN; /* I2S on GPIO_6-8 and 11-12 [Bit 26] - clear only! */ if (pin_mode == GPIO_PIN) bits |= ATH_GPIO_FUNCTION_I2S0_EN; if (gpio_pin == 12) { /* Enables I2S_SD on GPIO_12 [FUNC_2 Bit 5] */ bits2 |= ATH_GPIO_FUNCTION_2_EN_I2WS_ON_0; } break; case 13: /* Enables Ethernet LED on GPIO_13 [Bit 13] */ bits |= ATH_GPIO_FUNCTION_ETH_SWITCH_LED0_EN; if (pin_mode == GPIO_PIN) /* Disable undocumented Function [Bit 8] (otherwise GPIO mode won't work) */ bits |= ATH_GPIO_FUNCTION_CLK_OBS1_ENABLE; if (pin_mode == GPIO_PIN) /* Disable TCK as SPDIF Serial out on GPIO_13 [Bit 30] - clear only! */ bits |= ATH_GPIO_FUNCTION_SPDIF_EN; break; case 14: case 15: case 16: /* Enables I2C LED on GPIO_14 - 16 [FUNC_2 Bit 1] */ bits2 |= ATH_GPIO_FUNCTION_2_I2S_ON_LED; break; default: return -1; } if (pin_mode == GPIO_PIN) { if (bits) ath_reg_rmw_clear(ATH_GPIO_FUNCTIONS, bits); if (bits2) ath_reg_rmw_clear(ATH_GPIO_FUNCTION_2, bits2); } else { if (bits) ath_reg_rmw_set(ATH_GPIO_FUNCTIONS, bits); if (bits2) ath_reg_rmw_set(ATH_GPIO_FUNCTION_2, bits2); } #elif defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) /*--- die rein generische Loesung: ---*/ switch (pin_mode) { /*--- Sonderfaelle: ---*/ case FUNCTION_TDM_FS: function = (pin_dir == GPIO_INPUT_PIN) ? GPIO_IN_SLIC_PCM_FS : GPIO_OUT_SLIC_PCM_FS; break; case FUNCTION_TDM_CLK: /*--- IN: SLIC_PCM_DCL (Doppelfunktion mit I2S_MCLK) ---*/ function = (pin_dir == GPIO_INPUT_PIN) ? GPIO_IN_I2S_MCLK : GPIO_OUT_SLIC_PCM_CLK; break; case FUNCTION_SPDIF_OUT: function = GPIO_OUT_SPDIF_OUT; /*--- function = GPIO_OUT_SPDIF_OUT_23; ---*/ /*--- printk(KERN_ERR"%s: pin=%d pin_mode=%d function=%x\n", __func__, gpio_pin, pin_mode, function); ---*/ ath_reg_rmw_set(ATH_GPIO_FUNCTIONS, ATH_GPIO_FUNCTION_SPDIF_EN | ATH_GPIO_FUNCTION_STEREO_EN); /*--- pr_err("%s: pin=%d function=%d - > %x\n", __func__, gpio_pin, function, ath_reg_rd(ATH_GPIO_FUNCTIONS)); ---*/ break; /*--- Funktion aus der hw-gpio-table ---*/ case FUNCTION_PIN: if ((current_gpio_table_size > gpio_pin) && (current_gpio_table[gpio_pin].func != IGNORE_FUNCTION)) { function = current_gpio_table[gpio_pin].func; } if (function == NO_FUNCTION) { pr_err("%s: error: no function-mode in gpio_table (%d)\n", __func__, gpio_pin); } /*--- pr_err("%s: pin=%d function=%d\n", __func__, gpio_pin, function); ---*/ /*--- Sonderfall I2S: AudioClock enablen ---*/ switch (function) { case GPIO_OUT_I2S_MCK: ath_reg_rmw_set(ATH_GPIO_FUNCTIONS, ATH_GPIO_FUNCTION_I2S_MCKEN); /*--- pr_err("%s: pin=%d function=%d - > %x\n", __func__, gpio_pin, function, ath_reg_rd(ATH_GPIO_FUNCTIONS)); ---*/ break; case GPIO_OUT_I2S_CLK: ath_reg_rmw_set(ATH_GPIO_FUNCTIONS, ATH_GPIO_FUNCTION_I2S_REFCLKEN); /*--- pr_err("%s: pin=%d function=%d - > %x\n", __func__, gpio_pin, function, ath_reg_rd(ATH_GPIO_FUNCTIONS)); ---*/ break; case GPIO_OUT_I2S_SD: ath_reg_rmw_set(ATH_GPIO_FUNCTIONS, ATH_GPIO_FUNCTION_I2S0_EN); /*--- pr_err("%s: pin=%d function=%d - > %x\n", __func__, gpio_pin, function, ath_reg_rd(ATH_GPIO_FUNCTIONS)); ---*/ break; case GPIO_OUT_I2S_WS: default: break; } break; case GPIO_PIN: break; default: pr_err("%s: error: no configuration exist for pin_mode=%d\n", __func__, pin_mode); break; } if (pin_dir == GPIO_INPUT_PIN) { ath_avm_gpio_infunction_set(gpio_pin, function); ath_gpio_config_input(gpio_pin); } else { ath_avm_gpio_outfunction_set(gpio_pin, function); ath_gpio_config_output(gpio_pin); } #endif /*--- #ifdef CONFIG_SOC_AR724X ---*/ return 0; } int ath_avm_gpio_ctrl(unsigned int gpio_pin, enum _hw_gpio_function pin_mode, enum _hw_gpio_direction pin_dir) { if (gpio_pin > ATH79_GPIO_IRQ_COUNT) { if ((gpio_pin >= 100) && (gpio_pin < 100 + ath_gpio_shiftreg_size)) { return (pin_dir == GPIO_INPUT_PIN) ? -1 : 0; // input on shift register not supported } if ((gpio_pin >= 200) && (gpio_pin < 300)) { return (pin_dir == GPIO_INPUT_PIN) ? -1 : 0; // input on lanphy-gpio not supported } return -1; } #if 0 pr_err("[%s] gpio=%u as %s(%d) direction=%s\n", __func__, gpio_pin, pin_mode == GPIO_PIN ? "gpio" : "function", pin_mode, pin_dir == GPIO_INPUT_PIN ? "input" : "output"); #endif ath_gpio_setup_pin_mode(gpio_pin, pin_mode, pin_dir); if (pin_mode == GPIO_PIN) { if (pin_dir == GPIO_INPUT_PIN) ath_gpio_config_input(gpio_pin); else ath_gpio_config_output(gpio_pin); } /*--- ath_avm_gpio_dump_registers(__func__); ---*/ return 0; } EXPORT_SYMBOL(ath_avm_gpio_ctrl); int ath_avm_gpio_out_bit(unsigned int gpio_pin, int value) { /*--- pr_err("{%s} gpio_pin %d value 0x%x\n", __func__, gpio_pin, value); ---*/ if ((gpio_pin >= 100) && (gpio_pin < 200)) { if (gpio_pin >= 100 + ath_gpio_shiftreg_size) { /*--- pr_err("{%s} error: invalid shift gpio %d\n", __func__, gpio_pin); ---*/ return -1; } if ((gpio_pin >= 100) && ath_gpio_shiftreg_size) { /*--- pr_err("{%s} avmnet_gpio %d value 0x%x\n", __func__, gpio_pin, value); ---*/ gpio_pin -= 100; ath_gpio_shift_register_load(1 << gpio_pin, (value ? 1 : 0) << gpio_pin); return 0; } } if ((gpio_pin >= 200) && (gpio_pin < 300)) { /*--- pr_err("{%s} avmnet_gpio %d value 0x%x\n", __func__, gpio_pin, value); ---*/ avmnet_gpio(gpio_pin - 200, value); } if (gpio_pin > ATH79_GPIO_IRQ_COUNT) { return -1; } ath_gpio_out_val(gpio_pin, value); return 0; } EXPORT_SYMBOL(ath_avm_gpio_out_bit); int ath_avm_gpio_in_bit(unsigned int gpio_pin) { /* wird von sammel-treiber verwendet */ if (gpio_pin > ATH79_GPIO_IRQ_COUNT) { return -1; // Invalid pin or shift register (input not supported) } return ath_gpio_in_val(gpio_pin) ? 1 : 0; } EXPORT_SYMBOL(ath_avm_gpio_in_bit); unsigned int ath_avm_gpio_in_value(void) { return ath_reg_rd(ATH_GPIO_IN); } EXPORT_SYMBOL(ath_avm_gpio_in_value); void ath_avm_gpio_set_bitmask(unsigned int mask, unsigned int value) { /* wird von sammel-treiber verwendet */ ath_reg_rmw_clear(ATH_GPIO_OUT, mask); ath_reg_rmw_set(ATH_GPIO_OUT, (value & mask)); } EXPORT_SYMBOL(ath_avm_gpio_set_bitmask); int gpio_get_value(unsigned int gpio) { #if 0 if (gpio < ath79_gpio_count) return __ath79_gpio_get_value(gpio); return __gpio_get_value(gpio); #else return ath_avm_gpio_in_bit(gpio); #endif } EXPORT_SYMBOL(gpio_get_value); void gpio_set_value(unsigned int gpio, int value) { #if 0 if (gpio < ath79_gpio_count) __ath79_gpio_set_value(gpio, value); else __gpio_set_value(gpio, value); #else ath_avm_gpio_out_bit(gpio, value); #endif } EXPORT_SYMBOL(gpio_set_value); int ath_avm_gpio_init(void) { #if defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA953X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) int gpio; #endif /*--- ath_avm_gpio_dump_registers(__func__); ---*/ ath_avm_gpio_first_handle = NULL; ath_avm_gpio_init_functions(); #if defined(CONFIG_SOC_QCN550X) avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_shift_rclk", &ath_gpio_shiftreg_rclk_pin, NULL); #endif #if defined(CONFIG_SOC_AR934X) || defined(CONFIG_SOC_QCA953X) || defined(CONFIG_SOC_QCA955X) || defined(CONFIG_SOC_QCA956X) || defined(CONFIG_SOC_QCN550X) avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_shift_clk", &ath_gpio_shiftreg_clk_pin, NULL); avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_shift_din", &ath_gpio_shiftreg_din_pin, NULL); avm_get_hw_config(AVM_HW_CONFIG_VERSION, "shift_register_size", &ath_gpio_shiftreg_size, NULL); if (avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_spi_cs_dis_dac", &gpio, NULL) == 0) { pr_debug("disable spi_cs_dac\n"); ath_avm_gpio_out_bit(gpio, 0); /*--- disable SPI_CS1-Access (or'd with SPDIF_OUT) ---*/ } if (avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_peregrine_reset", &gpio, NULL) == 0) { pr_debug("Peregrine out of reset\n"); ath_avm_gpio_out_bit(gpio, 1); /*--- disable RESET ---*/ } if (avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_usb_reset", &gpio, NULL) == 0) { ath_avm_gpio_out_bit(gpio, 0); /*--- enable RESET ---*/ } /* == Activate UART_IN Functionality == */ if (avm_get_hw_config(AVM_HW_CONFIG_VERSION, "gpio_avm_uart_rx", &gpio, NULL) == 0) { pr_err("Enabling UART-Input for Pin %d\n", gpio); ath_reg_rmw_clear(ATH_GPIO_IN_ENABLE0, 0xff << 8); ath_reg_rmw_set(ATH_GPIO_IN_ENABLE0, (gpio & 0xff) << 8); } #endif return 0; } EXPORT_SYMBOL(ath_avm_gpio_init);