OpenWrt WiFi Driver Configuration: Complete ath9k Device-Tree Guide

OpenWrt configures Atheros ath9k WiFi chipsets through device-tree nodes, the kmod-ath9k kernel module, and hot-plug firmware scripts that load calibration EEPROM data at boot.

OpenWrt supports PCI-based Atheros WiFi hardware via the ath9k driver integrated through the mac80211 package in the openwrt/openwrt repository. This OpenWrt WiFi driver configuration relies on hardware descriptions in the device-tree for chip discovery, GPIO mapping, and EEPROM handling, supplemented by build system integration that packages the correct kernel modules and firmware handlers.

How the ath9k Driver Is Loaded

The ath9k driver is part of the mac80211 subsystem and binds to PCI devices automatically when the correct kernel module is present.

Kernel Module Packaging

OpenWrt includes the ath9k driver via the kmod-ath9k package, which builds from the mac80211 source tree. Device targets add this module to their default image through DEVICE_PACKAGES directives in target-specific makefiles:

DEVICE_PACKAGES += kmod-ath9k wpad-basic-mbedtls

For example, in target/linux/mvebu/image/cortexa9.mk, boards append ath9k support alongside wireless authentication packages (lines 108–114)【/cache/repos/github.com/openwrt/openwrt/main/target/linux/mvebu/image/cortexa9.mk#L108-L114】. Similarly, MT7621 profiles include the module in target/linux/ramips/image/mt7621.mk (line 2251)【/cache/repos/github.com/openwrt/openwrt/main/target/linux/ramips/image/mt7621.mk#L2251】.

PCI Auto-Probe Mechanism

When the kernel detects a PCI device with vendor ID 0x168c and device ID 0x0030 (Atheros AR9xxx series), the ath9k driver binds automatically. No additional udev rules or manual loading scripts are required, as the driver registers the standard pci168c,0030 compatible string during initialization.

Device-Tree Configuration for ath9k

The device-tree (DT) supplies hardware-specific parameters including EEPROM handling, MAC address sources, and GPIO mappings for LEDs.

Defining the WiFi Node

The ath9k chip appears as a child node under the PCI controller. In target/linux/ramips/dts/mt7621_mikrotik_ltap-2hnd.dts, the WiFi node uses the following structure:

&pcie0 {
    status = "okay";

    ath9k: wifi@0,0 {
        compatible = "pci168c,0030";
        reg = <0x0000 0 0 0 0>;
        qca,no-eeprom;
        nvmem-cells = <&macaddr_hard 1>;
        nvmem-cell-names = "mac-address";
        gpio-controller;
        #gpio-cells = <2>;
    };
};

(Source: target/linux/ramips/dts/mt7621_mikrotik_ltap-2hnd.dts lines 46–57【/cache/repos/github.com/openwrt/openwrt/main/target/linux/ramips/dts/mt7621_mikrotik_ltap-2hnd.dts#L46-L57】)

The qca,no-eeprom property disables automatic EEPROM loading from the card, forcing the driver to rely on external firmware files. The nvmem-cells property links the wireless MAC address to a specific offset in factory partition data.

Mapping LEDs to GPIO Pins

The driver exposes internal GPIOs for signal strength indicators through a dedicated sub-node. The following DT excerpt maps five RSSI LEDs to ath9k GPIO pins:

ath9k-leds {
    compatible = "gpio-leds";

    rssi0 { label = "green:rssi0"; gpios = <&ath9k 0 GPIO_ACTIVE_LOW>; };
    rssi1 { label = "green:rssi1"; gpios = <&ath9k 1 GPIO_ACTIVE_LOW>; };
    rssi2 { label = "green:rssi2"; gpios = <&ath9k 2 GPIO_ACTIVE_LOW>; };
    rssi3 { label = "green:rssi3"; gpios = <&ath9k 3 GPIO_ACTIVE_LOW>; };
    rssi4 { label = "green:rssi4"; gpios = <&ath9k 4 GPIO_ACTIVE_LOW>; };
};

(Source: target/linux/ramips/dts/mt7621_mikrotik_ltap-2hnd.dts lines 17–40【/cache/repos/github.com/openwrt/openwrt/main/target/linux/ramips/dts/mt7621_mikrotik_ltap-2hnd.dts#L17-L40】)

For this mapping to function, the driver must export GPIOs by setting gpio-controller and #gpio-cells = <2> in the parent WiFi node.

EEPROM and Calibration Data

When qca,no-eeprom is absent, the driver searches for ath9k-eeprom-pci-0000:01:00.0.bin (matching the PCI address) under /lib/firmware. OpenWrt provides calibration data through hot-plug scripts located at:


target/linux/*/base-files/etc/hotplug.d/firmware/10-ath9k-eeprom

These scripts copy the appropriate binary from persistent storage (such as a factory partition) to /lib/firmware during boot, ensuring the driver receives valid calibration data for regulatory compliance and power tuning.

Build System Integration

Beyond device-tree definitions, OpenWrt integrates ath9k support through Makefile configurations and kernel patches.

Device Package Makefiles

Target-specific image makefiles declare ath9k as a default package. The build system references these when generating firmware images for specific boards.

ath9k Patch Series

Hardware-specific patches reside in package/kernel/mac80211/patches/ath9k/. Critical patches include:

  • 341-wifi-ath9k-obtain-system-gpios.patch: Enables system-wide GPIO lookup for LED control
  • 530-ath9k_extra_leds.patch: Adds support for additional LED triggers and RSSI monitoring

These patches apply automatically when building the kmod-ath9k package, extending the upstream driver for OpenWrt's LED infrastructure.

Runtime Wireless Configuration

Once the kernel module loads successfully, OpenWrt's wireless configuration (/etc/config/wireless) references the interface using the mac80211 type and the PCI path from the device-tree:

config wifi-device 'radio0'
    option type     'mac80211'
    option hwmode   '11g'
    option path     'pci0000:01/0000:01:00.0'
    option channel  '11'
    option country  'US'
    option disabled '0'
    option htmode   'HT20'

config wifi-iface
    option device   'radio0'
    option network  'lan'
    option mode     'ap'
    option ssid     'OpenWrt'
    option encryption 'psk2'
    option key      'your-password'

The path option must match the PCI device hierarchy defined in the device-tree for the driver to attach correctly to the radio configuration.

Debugging Common ath9k Issues

When the wireless interface fails to initialize or behaves unexpectedly, verify these common configuration points:

  • No interface appears: Confirm kmod-ath9k is installed using lsmod | grep ath9k. If missing, add it to DEVICE_PACKAGES in the target Makefile and rebuild.
  • LEDs remain dark: Check that the ath9k-leds device-tree node exists and GPIO numbers match the chip's exported pins. Review dmesg | grep ath9k for GPIO registration errors.
  • Incorrect MAC address: Remove qca,no-eeprom from the device-tree to allow EEPROM loading, or ensure the calibration binary exists in /lib/firmware with the correct PCI address in the filename.
  • Unstable connections: Verify power regulator definitions in the device-tree, particularly for pcie_vcc_reg nodes supplying voltage to the WiFi card.

Summary

  • OpenWrt configures ath9k through the kmod-ath9k package integrated in target-specific makefiles like target/linux/mvebu/image/cortexa9.mk.
  • The device-tree defines the PCI node with compatible = "pci168c,0030", optional qca,no-eeprom, and GPIO controller properties for LED support.
  • Hot-plug scripts in target/linux/*/base-files/etc/hotplug.d/firmware/ provision calibration EEPROM binaries to /lib/firmware at boot.
  • mac80211 patches in package/kernel/mac80211/patches/ath9k/ extend the driver for OpenWrt's GPIO LED infrastructure.
  • Runtime configuration uses standard /etc/config/wireless with the PCI path matching the device-tree reg property.

Frequently Asked Questions

How do I enable LED support for ath9k in OpenWrt?

Add an ath9k-leds sub-node under the device-tree root with compatible = "gpio-leds", then define individual LED entries using gpios = <&ath9k N GPIO_ACTIVE_LOW> where N is the GPIO number. Ensure the parent WiFi node declares gpio-controller and #gpio-cells = <2> to export the chip's internal pins.

What does the qca,no-eeprom property do in the device-tree?

This property instructs the driver to skip automatic EEPROM loading from the WiFi card. When present, the driver relies on firmware files in /lib/firmware supplied by hot-plug scripts, or uses factory partition aliases via nvmem-cells for calibration data and MAC addresses.

Why is my ath9k wireless interface not showing up after boot?

Verify the PCI ID matches 0x168c:0x0030 using lspci, confirm kmod-ath9k is loaded with lsmod | grep ath9k, and check that the device-tree node uses compatible = "pci168c,0030". Also ensure the path option in /etc/config/wireless correctly reflects the PCI bus hierarchy from the device-tree.

Where does OpenWrt store ath9k calibration data?

Calibration binaries follow the naming pattern ath9k-eeprom-pci-0000:01:00.0.bin (adjusting the PCI address to match your hardware) and reside in /lib/firmware. OpenWrt populates these files at boot through 10-ath9k-eeprom hot-plug scripts that extract data from the device's factory partition or persistent storage.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →