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