Commit 4682bb8e authored by Hans de Goede's avatar Hans de Goede Committed by Jiri Kosina
Browse files

HID: lg-g15: Add support for the G510's M1-M3 and MR LEDs



Add support for controlling the LEDs below the M1-M3 and MR keys
on the G510.

Signed-off-by: default avatarHans de Goede <hdegoede@redhat.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 1f8cde2a
Loading
Loading
Loading
Loading
+90 −3
Original line number Original line Diff line number Diff line
@@ -353,6 +353,90 @@ static void lg_g510_leds_sync_work(struct work_struct *work)
	mutex_unlock(&g15->mutex);
	mutex_unlock(&g15->mutex);
}
}


static int lg_g510_update_mkey_led_brightness(struct lg_g15_data *g15)
{
	int ret;

	ret = hid_hw_raw_request(g15->hdev, LG_G510_FEATURE_M_KEYS_LEDS,
				 g15->transfer_buf, 2,
				 HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
	if (ret != 2) {
		hid_err(g15->hdev, "Error getting LED brightness: %d\n", ret);
		ret = (ret < 0) ? ret : -EIO;
	}

	g15->leds[LG_G15_MACRO_PRESET1].brightness =
		!!(g15->transfer_buf[1] & 0x80);
	g15->leds[LG_G15_MACRO_PRESET2].brightness =
		!!(g15->transfer_buf[1] & 0x40);
	g15->leds[LG_G15_MACRO_PRESET3].brightness =
		!!(g15->transfer_buf[1] & 0x20);
	g15->leds[LG_G15_MACRO_RECORD].brightness =
		!!(g15->transfer_buf[1] & 0x10);

	return 0;
}

static enum led_brightness lg_g510_mkey_led_get(struct led_classdev *led_cdev)
{
	struct lg_g15_led *g15_led =
		container_of(led_cdev, struct lg_g15_led, cdev);
	struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
	enum led_brightness brightness;

	mutex_lock(&g15->mutex);
	lg_g510_update_mkey_led_brightness(g15);
	brightness = g15->leds[g15_led->led].brightness;
	mutex_unlock(&g15->mutex);

	return brightness;
}

static int lg_g510_mkey_led_set(struct led_classdev *led_cdev,
				enum led_brightness brightness)
{
	struct lg_g15_led *g15_led =
		container_of(led_cdev, struct lg_g15_led, cdev);
	struct lg_g15_data *g15 = dev_get_drvdata(led_cdev->dev->parent);
	u8 val, mask = 0;
	int i, ret;

	/* Ignore LED off on unregister / keyboard unplug */
	if (led_cdev->flags & LED_UNREGISTERING)
		return 0;

	mutex_lock(&g15->mutex);

	for (i = LG_G15_MACRO_PRESET1; i < LG_G15_LED_MAX; i++) {
		if (i == g15_led->led)
			val = brightness;
		else
			val = g15->leds[i].brightness;

		if (val)
			mask |= 0x80 >> (i - LG_G15_MACRO_PRESET1);
	}

	g15->transfer_buf[0] = LG_G510_FEATURE_M_KEYS_LEDS;
	g15->transfer_buf[1] = mask;

	ret = hid_hw_raw_request(g15->hdev, LG_G510_FEATURE_M_KEYS_LEDS,
				 g15->transfer_buf, 2,
				 HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
	if (ret == 2) {
		/* Success */
		g15_led->brightness = brightness;
		ret = 0;
	} else {
		hid_err(g15->hdev, "Error setting LED brightness: %d\n", ret);
		ret = (ret < 0) ? ret : -EIO;
	}

	mutex_unlock(&g15->mutex);

	return ret;
}

/******** Generic LED functions ********/
/******** Generic LED functions ********/
static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
{
{
@@ -372,7 +456,7 @@ static int lg_g15_get_initial_led_brightness(struct lg_g15_data *g15)
		if (ret)
		if (ret)
			return ret;
			return ret;


		return 0;
		return lg_g510_update_mkey_led_brightness(g15);
	}
	}
	return -EINVAL; /* Never reached */
	return -EINVAL; /* Never reached */
}
}
@@ -606,8 +690,11 @@ static int lg_g15_register_led(struct lg_g15_data *g15, int i)
			g15->leds[i].cdev.groups = lg_g510_kbd_led_groups;
			g15->leds[i].cdev.groups = lg_g510_kbd_led_groups;
			break;
			break;
		default:
		default:
			/* TODO: Add support for M1 - M3 and MR leds */
			g15->leds[i].cdev.brightness_set_blocking =
			return 0;
				lg_g510_mkey_led_set;
			g15->leds[i].cdev.brightness_get =
				lg_g510_mkey_led_get;
			g15->leds[i].cdev.max_brightness = 1;
		}
		}
		break;
		break;
	}
	}