Skip to content

Commit

Permalink
fujitsu-laptop: Support radio LED
Browse files Browse the repository at this point in the history
Lifebook E734/E744/E754 has a LED which the manual calls "radio
components indicator".  It should be lit when any radio transmitter is
enabled.  Its state can be read and set using ACPI (FUNC interface,
RFKILL method).

Since the Lifebook E734/E744/E754 only has a button (as compared to a
slider) for enabling/disabling radio transmitters, I believe the LED in
question is meant to indicate whether all radio transmitters are
currently on or off.  However, pressing the radio toggle button does not
automatically change the hardware state of the transmitters: it looks
like this machine relies on soft rfkill.

As for detecting whether the LED is present on a given machine, I had to
resort to educated guesswork.  I assumed this LED is present on all
devices which have a radio toggle button instead of a slider.  My
Lifebook E744 holds 0x01010001 in BTNI.  By comparing the bits and
buttons with those of a Lifebook E8420 (BTNI=0x000F0101, has a slider),
I put my money on bit 24 as the indicator of the radio toggle button
being present.  Furthermore, bit 24 is also clear on the S7020 which
does not have the toggle button or an RF LED.

Figuring out how the LED is controlled was more deterministic as all it
took was decompiling the DSDT and taking a look at method S000 (the
RFKILL method of the FUNC interface).

The LED control method implemented here is unsuitable for use with
"heavy" LED triggers, like phy0rx.  Once blinking frequency achieves a
certain level, the system hangs.

Signed-off-by: Michał Kępień <kernel@kempniu.pl>
[jwoithe: Comment on bit 24 in BTNI, expanded commit msg]
Signed-off-by: Jonathan Woithe <jwoithe@just42.net>
[dvhart: Minor style and commit log adjustments]
Signed-off-by: Darren Hart <dvhart@linux.intel.com>
  • Loading branch information
Michał Kępień authored and Darren Hart committed Apr 15, 2016
1 parent 9735a22 commit 4f62568
Showing 1 changed file with 51 additions and 0 deletions.
51 changes: 51 additions & 0 deletions drivers/platform/x86/fujitsu-laptop.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@
#define KEYBOARD_LAMPS 0x100
#define LOGOLAMP_POWERON 0x2000
#define LOGOLAMP_ALWAYS 0x4000
#define RADIO_LED_ON 0x20
#endif

/* Hotkey details */
Expand Down Expand Up @@ -174,6 +175,7 @@ struct fujitsu_hotkey_t {
int rfkill_state;
int logolamp_registered;
int kblamps_registered;
int radio_led_registered;
};

static struct fujitsu_hotkey_t *fujitsu_hotkey;
Expand All @@ -200,6 +202,16 @@ static struct led_classdev kblamps_led = {
.brightness_get = kblamps_get,
.brightness_set = kblamps_set
};

static enum led_brightness radio_led_get(struct led_classdev *cdev);
static void radio_led_set(struct led_classdev *cdev,
enum led_brightness brightness);

static struct led_classdev radio_led = {
.name = "fujitsu::radio_led",
.brightness_get = radio_led_get,
.brightness_set = radio_led_set
};
#endif

#ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
Expand Down Expand Up @@ -275,6 +287,15 @@ static void kblamps_set(struct led_classdev *cdev,
call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
}

static void radio_led_set(struct led_classdev *cdev,
enum led_brightness brightness)
{
if (brightness >= LED_FULL)
call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, RADIO_LED_ON);
else
call_fext_func(FUNC_RFKILL, 0x5, RADIO_LED_ON, 0x0);
}

static enum led_brightness logolamp_get(struct led_classdev *cdev)
{
enum led_brightness brightness = LED_OFF;
Expand All @@ -299,6 +320,16 @@ static enum led_brightness kblamps_get(struct led_classdev *cdev)

return brightness;
}

static enum led_brightness radio_led_get(struct led_classdev *cdev)
{
enum led_brightness brightness = LED_OFF;

if (call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0) & RADIO_LED_ON)
brightness = LED_FULL;

return brightness;
}
#endif

/* Hardware access for LCD brightness control */
Expand Down Expand Up @@ -895,6 +926,23 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
result);
}
}

/*
* BTNI bit 24 seems to indicate the presence of a radio toggle
* button in place of a slide switch, and all such machines appear
* to also have an RF LED. Therefore use bit 24 as an indicator
* that an RF LED is present.
*/
if (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) & BIT(24)) {
result = led_classdev_register(&fujitsu->pf_device->dev,
&radio_led);
if (result == 0) {
fujitsu_hotkey->radio_led_registered = 1;
} else {
pr_err("Could not register LED handler for radio LED, error %i\n",
result);
}
}
#endif

return result;
Expand All @@ -921,6 +969,9 @@ static int acpi_fujitsu_hotkey_remove(struct acpi_device *device)

if (fujitsu_hotkey->kblamps_registered)
led_classdev_unregister(&kblamps_led);

if (fujitsu_hotkey->radio_led_registered)
led_classdev_unregister(&radio_led);
#endif

input_unregister_device(input);
Expand Down

0 comments on commit 4f62568

Please sign in to comment.