162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci Broadcom B43 wireless driver 562306a36Sopenharmony_ci RFKILL support 662306a36Sopenharmony_ci 762306a36Sopenharmony_ci Copyright (c) 2007 Michael Buesch <m@bues.ch> 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci*/ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include "radio.h" 1362306a36Sopenharmony_ci#include "b43legacy.h" 1462306a36Sopenharmony_ci 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci/* Returns TRUE, if the radio is enabled in hardware. */ 1762306a36Sopenharmony_cibool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev) 1862306a36Sopenharmony_ci{ 1962306a36Sopenharmony_ci if (dev->dev->id.revision >= 3) { 2062306a36Sopenharmony_ci if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI) 2162306a36Sopenharmony_ci & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK)) 2262306a36Sopenharmony_ci return true; 2362306a36Sopenharmony_ci } else { 2462306a36Sopenharmony_ci /* To prevent CPU fault on PPC, do not read a register 2562306a36Sopenharmony_ci * unless the interface is started; however, on resume 2662306a36Sopenharmony_ci * for hibernation, this routine is entered early. When 2762306a36Sopenharmony_ci * that happens, unconditionally return TRUE. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci if (b43legacy_status(dev) < B43legacy_STAT_STARTED) 3062306a36Sopenharmony_ci return true; 3162306a36Sopenharmony_ci if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO) 3262306a36Sopenharmony_ci & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK) 3362306a36Sopenharmony_ci return true; 3462306a36Sopenharmony_ci } 3562306a36Sopenharmony_ci return false; 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* The poll callback for the hardware button. */ 3962306a36Sopenharmony_civoid b43legacy_rfkill_poll(struct ieee80211_hw *hw) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw); 4262306a36Sopenharmony_ci struct b43legacy_wldev *dev = wl->current_dev; 4362306a36Sopenharmony_ci struct ssb_bus *bus = dev->dev->bus; 4462306a36Sopenharmony_ci bool enabled; 4562306a36Sopenharmony_ci bool brought_up = false; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci mutex_lock(&wl->mutex); 4862306a36Sopenharmony_ci if (unlikely(b43legacy_status(dev) < B43legacy_STAT_INITIALIZED)) { 4962306a36Sopenharmony_ci if (ssb_bus_powerup(bus, 0)) { 5062306a36Sopenharmony_ci mutex_unlock(&wl->mutex); 5162306a36Sopenharmony_ci return; 5262306a36Sopenharmony_ci } 5362306a36Sopenharmony_ci ssb_device_enable(dev->dev, 0); 5462306a36Sopenharmony_ci brought_up = true; 5562306a36Sopenharmony_ci } 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci enabled = b43legacy_is_hw_radio_enabled(dev); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci if (unlikely(enabled != dev->radio_hw_enable)) { 6062306a36Sopenharmony_ci dev->radio_hw_enable = enabled; 6162306a36Sopenharmony_ci b43legacyinfo(wl, "Radio hardware status changed to %s\n", 6262306a36Sopenharmony_ci enabled ? "ENABLED" : "DISABLED"); 6362306a36Sopenharmony_ci wiphy_rfkill_set_hw_state(hw->wiphy, !enabled); 6462306a36Sopenharmony_ci if (enabled != dev->phy.radio_on) { 6562306a36Sopenharmony_ci if (enabled) 6662306a36Sopenharmony_ci b43legacy_radio_turn_on(dev); 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci b43legacy_radio_turn_off(dev, 0); 6962306a36Sopenharmony_ci } 7062306a36Sopenharmony_ci } 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci if (brought_up) { 7362306a36Sopenharmony_ci ssb_device_disable(dev->dev, 0); 7462306a36Sopenharmony_ci ssb_bus_may_powerdown(bus); 7562306a36Sopenharmony_ci } 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci mutex_unlock(&wl->mutex); 7862306a36Sopenharmony_ci} 79