18c2ecf20Sopenharmony_ci/* 28c2ecf20Sopenharmony_ci * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> 38c2ecf20Sopenharmony_ci * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any 68c2ecf20Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 78c2ecf20Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 108c2ecf20Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 118c2ecf20Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 128c2ecf20Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 138c2ecf20Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 148c2ecf20Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 158c2ecf20Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci 198c2ecf20Sopenharmony_ci/****************\ 208c2ecf20Sopenharmony_ci GPIO Functions 218c2ecf20Sopenharmony_ci\****************/ 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "ath5k.h" 248c2ecf20Sopenharmony_ci#include "reg.h" 258c2ecf20Sopenharmony_ci#include "debug.h" 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci 288c2ecf20Sopenharmony_ci/** 298c2ecf20Sopenharmony_ci * DOC: GPIO/LED functions 308c2ecf20Sopenharmony_ci * 318c2ecf20Sopenharmony_ci * Here we control the 6 bidirectional GPIO pins provided by the hw. 328c2ecf20Sopenharmony_ci * We can set a GPIO pin to be an input or an output pin on GPIO control 338c2ecf20Sopenharmony_ci * register and then read or set its status from GPIO data input/output 348c2ecf20Sopenharmony_ci * registers. 358c2ecf20Sopenharmony_ci * 368c2ecf20Sopenharmony_ci * We also control the two LED pins provided by the hw, LED_0 is our 378c2ecf20Sopenharmony_ci * "power" LED and LED_1 is our "network activity" LED but many scenarios 388c2ecf20Sopenharmony_ci * are available from hw. Vendors might also provide LEDs connected to the 398c2ecf20Sopenharmony_ci * GPIO pins, we handle them through the LED subsystem on led.c 408c2ecf20Sopenharmony_ci */ 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_ci/** 448c2ecf20Sopenharmony_ci * ath5k_hw_set_ledstate() - Set led state 458c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 468c2ecf20Sopenharmony_ci * @state: One of AR5K_LED_* 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * Used to set the LED blinking state. This only 498c2ecf20Sopenharmony_ci * works for the LED connected to the LED_0, LED_1 pins, 508c2ecf20Sopenharmony_ci * not the GPIO based. 518c2ecf20Sopenharmony_ci */ 528c2ecf20Sopenharmony_civoid 538c2ecf20Sopenharmony_ciath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) 548c2ecf20Sopenharmony_ci{ 558c2ecf20Sopenharmony_ci u32 led; 568c2ecf20Sopenharmony_ci /*5210 has different led mode handling*/ 578c2ecf20Sopenharmony_ci u32 led_5210; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci /*Reset led status*/ 608c2ecf20Sopenharmony_ci if (ah->ah_version != AR5K_AR5210) 618c2ecf20Sopenharmony_ci AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, 628c2ecf20Sopenharmony_ci AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); 638c2ecf20Sopenharmony_ci else 648c2ecf20Sopenharmony_ci AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); 658c2ecf20Sopenharmony_ci 668c2ecf20Sopenharmony_ci /* 678c2ecf20Sopenharmony_ci * Some blinking values, define at your wish 688c2ecf20Sopenharmony_ci */ 698c2ecf20Sopenharmony_ci switch (state) { 708c2ecf20Sopenharmony_ci case AR5K_LED_SCAN: 718c2ecf20Sopenharmony_ci case AR5K_LED_AUTH: 728c2ecf20Sopenharmony_ci led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; 738c2ecf20Sopenharmony_ci led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; 748c2ecf20Sopenharmony_ci break; 758c2ecf20Sopenharmony_ci 768c2ecf20Sopenharmony_ci case AR5K_LED_INIT: 778c2ecf20Sopenharmony_ci led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; 788c2ecf20Sopenharmony_ci led_5210 = AR5K_PCICFG_LED_PEND; 798c2ecf20Sopenharmony_ci break; 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci case AR5K_LED_ASSOC: 828c2ecf20Sopenharmony_ci case AR5K_LED_RUN: 838c2ecf20Sopenharmony_ci led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; 848c2ecf20Sopenharmony_ci led_5210 = AR5K_PCICFG_LED_ASSOC; 858c2ecf20Sopenharmony_ci break; 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci default: 888c2ecf20Sopenharmony_ci led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; 898c2ecf20Sopenharmony_ci led_5210 = AR5K_PCICFG_LED_PEND; 908c2ecf20Sopenharmony_ci break; 918c2ecf20Sopenharmony_ci } 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /*Write new status to the register*/ 948c2ecf20Sopenharmony_ci if (ah->ah_version != AR5K_AR5210) 958c2ecf20Sopenharmony_ci AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); 968c2ecf20Sopenharmony_ci else 978c2ecf20Sopenharmony_ci AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); 988c2ecf20Sopenharmony_ci} 998c2ecf20Sopenharmony_ci 1008c2ecf20Sopenharmony_ci/** 1018c2ecf20Sopenharmony_ci * ath5k_hw_set_gpio_input() - Set GPIO inputs 1028c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 1038c2ecf20Sopenharmony_ci * @gpio: GPIO pin to set as input 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ciint 1068c2ecf20Sopenharmony_ciath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) 1078c2ecf20Sopenharmony_ci{ 1088c2ecf20Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 1098c2ecf20Sopenharmony_ci return -EINVAL; 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci ath5k_hw_reg_write(ah, 1128c2ecf20Sopenharmony_ci (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) 1138c2ecf20Sopenharmony_ci | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci return 0; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/** 1198c2ecf20Sopenharmony_ci * ath5k_hw_set_gpio_output() - Set GPIO outputs 1208c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 1218c2ecf20Sopenharmony_ci * @gpio: The GPIO pin to set as output 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_ciint 1248c2ecf20Sopenharmony_ciath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) 1258c2ecf20Sopenharmony_ci{ 1268c2ecf20Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 1278c2ecf20Sopenharmony_ci return -EINVAL; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci ath5k_hw_reg_write(ah, 1308c2ecf20Sopenharmony_ci (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) 1318c2ecf20Sopenharmony_ci | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci/** 1378c2ecf20Sopenharmony_ci * ath5k_hw_get_gpio() - Get GPIO state 1388c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 1398c2ecf20Sopenharmony_ci * @gpio: The GPIO pin to read 1408c2ecf20Sopenharmony_ci */ 1418c2ecf20Sopenharmony_ciu32 1428c2ecf20Sopenharmony_ciath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) 1438c2ecf20Sopenharmony_ci{ 1448c2ecf20Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 1458c2ecf20Sopenharmony_ci return 0xffffffff; 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci /* GPIO input magic */ 1488c2ecf20Sopenharmony_ci return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & 1498c2ecf20Sopenharmony_ci 0x1; 1508c2ecf20Sopenharmony_ci} 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci/** 1538c2ecf20Sopenharmony_ci * ath5k_hw_set_gpio() - Set GPIO state 1548c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 1558c2ecf20Sopenharmony_ci * @gpio: The GPIO pin to set 1568c2ecf20Sopenharmony_ci * @val: Value to set (boolean) 1578c2ecf20Sopenharmony_ci */ 1588c2ecf20Sopenharmony_ciint 1598c2ecf20Sopenharmony_ciath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) 1608c2ecf20Sopenharmony_ci{ 1618c2ecf20Sopenharmony_ci u32 data; 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 1648c2ecf20Sopenharmony_ci return -EINVAL; 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci /* GPIO output magic */ 1678c2ecf20Sopenharmony_ci data = ath5k_hw_reg_read(ah, AR5K_GPIODO); 1688c2ecf20Sopenharmony_ci 1698c2ecf20Sopenharmony_ci data &= ~(1 << gpio); 1708c2ecf20Sopenharmony_ci data |= (val & 1) << gpio; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci ath5k_hw_reg_write(ah, data, AR5K_GPIODO); 1738c2ecf20Sopenharmony_ci 1748c2ecf20Sopenharmony_ci return 0; 1758c2ecf20Sopenharmony_ci} 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_ci/** 1788c2ecf20Sopenharmony_ci * ath5k_hw_set_gpio_intr() - Initialize the GPIO interrupt (RFKill switch) 1798c2ecf20Sopenharmony_ci * @ah: The &struct ath5k_hw 1808c2ecf20Sopenharmony_ci * @gpio: The GPIO pin to use 1818c2ecf20Sopenharmony_ci * @interrupt_level: True to generate interrupt on active pin (high) 1828c2ecf20Sopenharmony_ci * 1838c2ecf20Sopenharmony_ci * This function is used to set up the GPIO interrupt for the hw RFKill switch. 1848c2ecf20Sopenharmony_ci * That switch is connected to a GPIO pin and it's number is stored on EEPROM. 1858c2ecf20Sopenharmony_ci * It can either open or close the circuit to indicate that we should disable 1868c2ecf20Sopenharmony_ci * RF/Wireless to save power (we also get that from EEPROM). 1878c2ecf20Sopenharmony_ci */ 1888c2ecf20Sopenharmony_civoid 1898c2ecf20Sopenharmony_ciath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, 1908c2ecf20Sopenharmony_ci u32 interrupt_level) 1918c2ecf20Sopenharmony_ci{ 1928c2ecf20Sopenharmony_ci u32 data; 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 1958c2ecf20Sopenharmony_ci return; 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * Set the GPIO interrupt 1998c2ecf20Sopenharmony_ci */ 2008c2ecf20Sopenharmony_ci data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & 2018c2ecf20Sopenharmony_ci ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | 2028c2ecf20Sopenharmony_ci AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | 2038c2ecf20Sopenharmony_ci (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci ath5k_hw_reg_write(ah, interrupt_level ? data : 2068c2ecf20Sopenharmony_ci (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_ci ah->ah_imr |= AR5K_IMR_GPIO; 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_ci /* Enable GPIO interrupts */ 2118c2ecf20Sopenharmony_ci AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); 2128c2ecf20Sopenharmony_ci} 2138c2ecf20Sopenharmony_ci 214