162306a36Sopenharmony_ci/* 262306a36Sopenharmony_ci * Copyright (c) 2004-2008 Reyk Floeter <reyk@openbsd.org> 362306a36Sopenharmony_ci * Copyright (c) 2006-2008 Nick Kossifidis <mickflemm@gmail.com> 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Permission to use, copy, modify, and distribute this software for any 662306a36Sopenharmony_ci * purpose with or without fee is hereby granted, provided that the above 762306a36Sopenharmony_ci * copyright notice and this permission notice appear in all copies. 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1062306a36Sopenharmony_ci * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1162306a36Sopenharmony_ci * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1262306a36Sopenharmony_ci * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1362306a36Sopenharmony_ci * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1462306a36Sopenharmony_ci * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1562306a36Sopenharmony_ci * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1662306a36Sopenharmony_ci * 1762306a36Sopenharmony_ci */ 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci/****************\ 2062306a36Sopenharmony_ci GPIO Functions 2162306a36Sopenharmony_ci\****************/ 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci#include "ath5k.h" 2462306a36Sopenharmony_ci#include "reg.h" 2562306a36Sopenharmony_ci#include "debug.h" 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_ci/** 2962306a36Sopenharmony_ci * DOC: GPIO/LED functions 3062306a36Sopenharmony_ci * 3162306a36Sopenharmony_ci * Here we control the 6 bidirectional GPIO pins provided by the hw. 3262306a36Sopenharmony_ci * We can set a GPIO pin to be an input or an output pin on GPIO control 3362306a36Sopenharmony_ci * register and then read or set its status from GPIO data input/output 3462306a36Sopenharmony_ci * registers. 3562306a36Sopenharmony_ci * 3662306a36Sopenharmony_ci * We also control the two LED pins provided by the hw, LED_0 is our 3762306a36Sopenharmony_ci * "power" LED and LED_1 is our "network activity" LED but many scenarios 3862306a36Sopenharmony_ci * are available from hw. Vendors might also provide LEDs connected to the 3962306a36Sopenharmony_ci * GPIO pins, we handle them through the LED subsystem on led.c 4062306a36Sopenharmony_ci */ 4162306a36Sopenharmony_ci 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci/** 4462306a36Sopenharmony_ci * ath5k_hw_set_ledstate() - Set led state 4562306a36Sopenharmony_ci * @ah: The &struct ath5k_hw 4662306a36Sopenharmony_ci * @state: One of AR5K_LED_* 4762306a36Sopenharmony_ci * 4862306a36Sopenharmony_ci * Used to set the LED blinking state. This only 4962306a36Sopenharmony_ci * works for the LED connected to the LED_0, LED_1 pins, 5062306a36Sopenharmony_ci * not the GPIO based. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_civoid 5362306a36Sopenharmony_ciath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci u32 led; 5662306a36Sopenharmony_ci /*5210 has different led mode handling*/ 5762306a36Sopenharmony_ci u32 led_5210; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci /*Reset led status*/ 6062306a36Sopenharmony_ci if (ah->ah_version != AR5K_AR5210) 6162306a36Sopenharmony_ci AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, 6262306a36Sopenharmony_ci AR5K_PCICFG_LEDMODE | AR5K_PCICFG_LED); 6362306a36Sopenharmony_ci else 6462306a36Sopenharmony_ci AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_LED); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci /* 6762306a36Sopenharmony_ci * Some blinking values, define at your wish 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ci switch (state) { 7062306a36Sopenharmony_ci case AR5K_LED_SCAN: 7162306a36Sopenharmony_ci case AR5K_LED_AUTH: 7262306a36Sopenharmony_ci led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_PEND; 7362306a36Sopenharmony_ci led_5210 = AR5K_PCICFG_LED_PEND | AR5K_PCICFG_LED_BCTL; 7462306a36Sopenharmony_ci break; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci case AR5K_LED_INIT: 7762306a36Sopenharmony_ci led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_NONE; 7862306a36Sopenharmony_ci led_5210 = AR5K_PCICFG_LED_PEND; 7962306a36Sopenharmony_ci break; 8062306a36Sopenharmony_ci 8162306a36Sopenharmony_ci case AR5K_LED_ASSOC: 8262306a36Sopenharmony_ci case AR5K_LED_RUN: 8362306a36Sopenharmony_ci led = AR5K_PCICFG_LEDMODE_PROP | AR5K_PCICFG_LED_ASSOC; 8462306a36Sopenharmony_ci led_5210 = AR5K_PCICFG_LED_ASSOC; 8562306a36Sopenharmony_ci break; 8662306a36Sopenharmony_ci 8762306a36Sopenharmony_ci default: 8862306a36Sopenharmony_ci led = AR5K_PCICFG_LEDMODE_PROM | AR5K_PCICFG_LED_NONE; 8962306a36Sopenharmony_ci led_5210 = AR5K_PCICFG_LED_PEND; 9062306a36Sopenharmony_ci break; 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci 9362306a36Sopenharmony_ci /*Write new status to the register*/ 9462306a36Sopenharmony_ci if (ah->ah_version != AR5K_AR5210) 9562306a36Sopenharmony_ci AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led); 9662306a36Sopenharmony_ci else 9762306a36Sopenharmony_ci AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, led_5210); 9862306a36Sopenharmony_ci} 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci/** 10162306a36Sopenharmony_ci * ath5k_hw_set_gpio_input() - Set GPIO inputs 10262306a36Sopenharmony_ci * @ah: The &struct ath5k_hw 10362306a36Sopenharmony_ci * @gpio: GPIO pin to set as input 10462306a36Sopenharmony_ci */ 10562306a36Sopenharmony_ciint 10662306a36Sopenharmony_ciath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio) 10762306a36Sopenharmony_ci{ 10862306a36Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 10962306a36Sopenharmony_ci return -EINVAL; 11062306a36Sopenharmony_ci 11162306a36Sopenharmony_ci ath5k_hw_reg_write(ah, 11262306a36Sopenharmony_ci (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) 11362306a36Sopenharmony_ci | AR5K_GPIOCR_IN(gpio), AR5K_GPIOCR); 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci return 0; 11662306a36Sopenharmony_ci} 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci/** 11962306a36Sopenharmony_ci * ath5k_hw_set_gpio_output() - Set GPIO outputs 12062306a36Sopenharmony_ci * @ah: The &struct ath5k_hw 12162306a36Sopenharmony_ci * @gpio: The GPIO pin to set as output 12262306a36Sopenharmony_ci */ 12362306a36Sopenharmony_ciint 12462306a36Sopenharmony_ciath5k_hw_set_gpio_output(struct ath5k_hw *ah, u32 gpio) 12562306a36Sopenharmony_ci{ 12662306a36Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 12762306a36Sopenharmony_ci return -EINVAL; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci ath5k_hw_reg_write(ah, 13062306a36Sopenharmony_ci (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & ~AR5K_GPIOCR_OUT(gpio)) 13162306a36Sopenharmony_ci | AR5K_GPIOCR_OUT(gpio), AR5K_GPIOCR); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci return 0; 13462306a36Sopenharmony_ci} 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci/** 13762306a36Sopenharmony_ci * ath5k_hw_get_gpio() - Get GPIO state 13862306a36Sopenharmony_ci * @ah: The &struct ath5k_hw 13962306a36Sopenharmony_ci * @gpio: The GPIO pin to read 14062306a36Sopenharmony_ci */ 14162306a36Sopenharmony_ciu32 14262306a36Sopenharmony_ciath5k_hw_get_gpio(struct ath5k_hw *ah, u32 gpio) 14362306a36Sopenharmony_ci{ 14462306a36Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 14562306a36Sopenharmony_ci return 0xffffffff; 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci /* GPIO input magic */ 14862306a36Sopenharmony_ci return ((ath5k_hw_reg_read(ah, AR5K_GPIODI) & AR5K_GPIODI_M) >> gpio) & 14962306a36Sopenharmony_ci 0x1; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci/** 15362306a36Sopenharmony_ci * ath5k_hw_set_gpio() - Set GPIO state 15462306a36Sopenharmony_ci * @ah: The &struct ath5k_hw 15562306a36Sopenharmony_ci * @gpio: The GPIO pin to set 15662306a36Sopenharmony_ci * @val: Value to set (boolean) 15762306a36Sopenharmony_ci */ 15862306a36Sopenharmony_ciint 15962306a36Sopenharmony_ciath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val) 16062306a36Sopenharmony_ci{ 16162306a36Sopenharmony_ci u32 data; 16262306a36Sopenharmony_ci 16362306a36Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 16462306a36Sopenharmony_ci return -EINVAL; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci /* GPIO output magic */ 16762306a36Sopenharmony_ci data = ath5k_hw_reg_read(ah, AR5K_GPIODO); 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci data &= ~(1 << gpio); 17062306a36Sopenharmony_ci data |= (val & 1) << gpio; 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci ath5k_hw_reg_write(ah, data, AR5K_GPIODO); 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci return 0; 17562306a36Sopenharmony_ci} 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci/** 17862306a36Sopenharmony_ci * ath5k_hw_set_gpio_intr() - Initialize the GPIO interrupt (RFKill switch) 17962306a36Sopenharmony_ci * @ah: The &struct ath5k_hw 18062306a36Sopenharmony_ci * @gpio: The GPIO pin to use 18162306a36Sopenharmony_ci * @interrupt_level: True to generate interrupt on active pin (high) 18262306a36Sopenharmony_ci * 18362306a36Sopenharmony_ci * This function is used to set up the GPIO interrupt for the hw RFKill switch. 18462306a36Sopenharmony_ci * That switch is connected to a GPIO pin and it's number is stored on EEPROM. 18562306a36Sopenharmony_ci * It can either open or close the circuit to indicate that we should disable 18662306a36Sopenharmony_ci * RF/Wireless to save power (we also get that from EEPROM). 18762306a36Sopenharmony_ci */ 18862306a36Sopenharmony_civoid 18962306a36Sopenharmony_ciath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio, 19062306a36Sopenharmony_ci u32 interrupt_level) 19162306a36Sopenharmony_ci{ 19262306a36Sopenharmony_ci u32 data; 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci if (gpio >= AR5K_NUM_GPIO) 19562306a36Sopenharmony_ci return; 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci /* 19862306a36Sopenharmony_ci * Set the GPIO interrupt 19962306a36Sopenharmony_ci */ 20062306a36Sopenharmony_ci data = (ath5k_hw_reg_read(ah, AR5K_GPIOCR) & 20162306a36Sopenharmony_ci ~(AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_SELH | 20262306a36Sopenharmony_ci AR5K_GPIOCR_INT_ENA | AR5K_GPIOCR_OUT(gpio))) | 20362306a36Sopenharmony_ci (AR5K_GPIOCR_INT_SEL(gpio) | AR5K_GPIOCR_INT_ENA); 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci ath5k_hw_reg_write(ah, interrupt_level ? data : 20662306a36Sopenharmony_ci (data | AR5K_GPIOCR_INT_SELH), AR5K_GPIOCR); 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci ah->ah_imr |= AR5K_IMR_GPIO; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci /* Enable GPIO interrupts */ 21162306a36Sopenharmony_ci AR5K_REG_ENABLE_BITS(ah, AR5K_PIMR, AR5K_IMR_GPIO); 21262306a36Sopenharmony_ci} 21362306a36Sopenharmony_ci 214