1f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen/* 2f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * MSI GT683R led driver 3f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * 4f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * Copyright (c) 2014 Janne Kanniainen <janne.kanniainen@gmail.com> 5f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * 6f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * This program is free software; you can redistribute it and/or 7f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * modify it under the terms of the GNU General Public License as 8f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * published by the Free Software Foundation; either version 2 of 9f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * the License, or (at your option) any later version. 10f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * 11f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * This program is distributed in the hope that it will be useful, 12f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * but WITHOUT ANY WARRANTY; without even the implied warranty of 13f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * GNU General Public License for more details. 15f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * 16f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen */ 17f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 18f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen#include <linux/device.h> 19f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen#include <linux/hid.h> 20f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen#include <linux/kernel.h> 21f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen#include <linux/leds.h> 22f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen#include <linux/module.h> 23f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 24f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen#include "hid-ids.h" 25f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 26f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen#define GT683R_BUFFER_SIZE 8 27f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 28f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen/* 29f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * GT683R_LED_OFF: all LEDs are off 30f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * GT683R_LED_AUDIO: LEDs brightness depends on sound level 31f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * GT683R_LED_BREATHING: LEDs brightness varies at human breathing rate 32f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen * GT683R_LED_NORMAL: LEDs are fully on when enabled 33f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen */ 34f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenenum gt683r_led_mode { 35f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen GT683R_LED_OFF = 0, 36f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen GT683R_LED_AUDIO = 2, 37f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen GT683R_LED_BREATHING = 3, 38f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen GT683R_LED_NORMAL = 5 39f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen}; 40f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 41f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenenum gt683r_panels { 42f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen GT683R_LED_BACK = 0, 43f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen GT683R_LED_SIDE = 1, 44f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen GT683R_LED_FRONT = 2, 45f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen GT683R_LED_COUNT, 46f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen}; 47f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 48f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic const char * const gt683r_panel_names[] = { 49f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen "back", 50f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen "side", 51f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen "front", 52f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen}; 53f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 54f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstruct gt683r_led { 55f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct hid_device *hdev; 56f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct led_classdev led_devs[GT683R_LED_COUNT]; 57f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct mutex lock; 58f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct work_struct work; 59f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen enum led_brightness brightnesses[GT683R_LED_COUNT]; 60f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen enum gt683r_led_mode mode; 61f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen}; 62f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 63f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic const struct hid_device_id gt683r_led_id[] = { 64f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen { HID_USB_DEVICE(USB_VENDOR_ID_MSI, USB_DEVICE_ID_MSI_GT683R_LED_PANEL) }, 65f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen { } 66f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen}; 67f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 68f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic void gt683r_brightness_set(struct led_classdev *led_cdev, 69f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen enum led_brightness brightness) 70f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 71f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int i; 72f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct device *dev = led_cdev->dev->parent; 73f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct hid_device *hdev = container_of(dev, struct hid_device, dev); 74f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct gt683r_led *led = hid_get_drvdata(hdev); 75f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 76f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen for (i = 0; i < GT683R_LED_COUNT; i++) { 77f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (led_cdev == &led->led_devs[i]) 78f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen break; 79f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 80f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 81f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (i < GT683R_LED_COUNT) { 82f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->brightnesses[i] = brightness; 83f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen schedule_work(&led->work); 84f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 85f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 86f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 876522fe1c39a79d4753e37d912876315720119f82Janne Kanniainenstatic ssize_t mode_show(struct device *dev, 88f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct device_attribute *attr, 89f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen char *buf) 90f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 91f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen u8 sysfs_mode; 926522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen struct hid_device *hdev = container_of(dev->parent, 936522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen struct hid_device, dev); 94f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct gt683r_led *led = hid_get_drvdata(hdev); 95f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 96f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (led->mode == GT683R_LED_NORMAL) 97f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen sysfs_mode = 0; 98f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen else if (led->mode == GT683R_LED_AUDIO) 99f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen sysfs_mode = 1; 100f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen else 101f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen sysfs_mode = 2; 102f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 103f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return scnprintf(buf, PAGE_SIZE, "%u\n", sysfs_mode); 104f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 105f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 1066522fe1c39a79d4753e37d912876315720119f82Janne Kanniainenstatic ssize_t mode_store(struct device *dev, 107f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct device_attribute *attr, 108f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen const char *buf, size_t count) 109f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 110f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen u8 sysfs_mode; 1116522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen struct hid_device *hdev = container_of(dev->parent, 1126522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen struct hid_device, dev); 113f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct gt683r_led *led = hid_get_drvdata(hdev); 114f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 115f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 116f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (kstrtou8(buf, 10, &sysfs_mode) || sysfs_mode > 2) 117f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return -EINVAL; 118f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 119f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen mutex_lock(&led->lock); 120f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 121f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (sysfs_mode == 0) 122f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->mode = GT683R_LED_NORMAL; 123f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen else if (sysfs_mode == 1) 124f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->mode = GT683R_LED_AUDIO; 125f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen else 126f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->mode = GT683R_LED_BREATHING; 127f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 128f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen mutex_unlock(&led->lock); 129f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen schedule_work(&led->work); 130f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 131f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return count; 132f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 133f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 134f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic int gt683r_led_snd_msg(struct gt683r_led *led, u8 *msg) 135f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 136f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int ret; 137f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 138f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen ret = hid_hw_raw_request(led->hdev, msg[0], msg, GT683R_BUFFER_SIZE, 139f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 140f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (ret != GT683R_BUFFER_SIZE) { 141f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen hid_err(led->hdev, 142f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen "failed to send set report request: %i\n", ret); 143f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (ret < 0) 144f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return ret; 145f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return -EIO; 146f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 147f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 148f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return 0; 149f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 150f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 151f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic int gt683r_leds_set(struct gt683r_led *led, u8 leds) 152f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 153f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int ret; 154f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen u8 *buffer; 155f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 156f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); 157f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (!buffer) 158f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return -ENOMEM; 159f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 160f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[0] = 0x01; 161f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[1] = 0x02; 162f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[2] = 0x30; 163f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[3] = leds; 164f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen ret = gt683r_led_snd_msg(led, buffer); 165f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 166f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen kfree(buffer); 167f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return ret; 168f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 169f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 170f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic int gt683r_mode_set(struct gt683r_led *led, u8 mode) 171f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 172f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int ret; 173f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen u8 *buffer; 174f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 175f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer = kzalloc(GT683R_BUFFER_SIZE, GFP_KERNEL); 176f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (!buffer) 177f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return -ENOMEM; 178f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 179f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[0] = 0x01; 180f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[1] = 0x02; 181f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[2] = 0x20; 182f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[3] = mode; 183f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen buffer[4] = 0x01; 184f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen ret = gt683r_led_snd_msg(led, buffer); 185f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 186f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen kfree(buffer); 187f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return ret; 188f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 189f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 190f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic void gt683r_led_work(struct work_struct *work) 191f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 192f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int i; 193f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen u8 leds = 0; 194f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen u8 mode; 195f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct gt683r_led *led = container_of(work, struct gt683r_led, work); 196f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 197f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen mutex_lock(&led->lock); 198f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 199f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen for (i = 0; i < GT683R_LED_COUNT; i++) { 200f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (led->brightnesses[i]) 201f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen leds |= BIT(i); 202f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 203f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 204f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (gt683r_leds_set(led, leds)) 205f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen goto fail; 206f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 207f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (leds) 208f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen mode = led->mode; 209f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen else 210f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen mode = GT683R_LED_OFF; 211f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 212f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen gt683r_mode_set(led, mode); 213f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenfail: 214f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen mutex_unlock(&led->lock); 215f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 216f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 2176522fe1c39a79d4753e37d912876315720119f82Janne Kanniainenstatic DEVICE_ATTR_RW(mode); 2186522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen 2196522fe1c39a79d4753e37d912876315720119f82Janne Kanniainenstatic struct attribute *gt683r_led_attrs[] = { 2206522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen &dev_attr_mode.attr, 2216522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen NULL 2226522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen}; 2236522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen 2246522fe1c39a79d4753e37d912876315720119f82Janne Kanniainenstatic const struct attribute_group gt683r_led_group = { 2256522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen .name = "gt683r", 2266522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen .attrs = gt683r_led_attrs, 2276522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen}; 2286522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen 2296522fe1c39a79d4753e37d912876315720119f82Janne Kanniainenstatic const struct attribute_group *gt683r_led_groups[] = { 2306522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen >683r_led_group, 2316522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen NULL 2326522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen}; 233f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 234f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic int gt683r_led_probe(struct hid_device *hdev, 235f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen const struct hid_device_id *id) 236f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 237f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int i; 238f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int ret; 239f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int name_sz; 240f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen char *name; 241f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct gt683r_led *led; 242f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 243f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led = devm_kzalloc(&hdev->dev, sizeof(*led), GFP_KERNEL); 244f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (!led) 245f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return -ENOMEM; 246f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 247c3883ae918c8754f7c251564d63211e1d5648b08Janne Kanniainen mutex_init(&led->lock); 248c3883ae918c8754f7c251564d63211e1d5648b08Janne Kanniainen INIT_WORK(&led->work, gt683r_led_work); 249c3883ae918c8754f7c251564d63211e1d5648b08Janne Kanniainen 250f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->mode = GT683R_LED_NORMAL; 251f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->hdev = hdev; 252f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen hid_set_drvdata(hdev, led); 253f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 254f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen ret = hid_parse(hdev); 255f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (ret) { 256f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen hid_err(hdev, "hid parsing failed\n"); 257f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return ret; 258f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 259f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 260f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); 261f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (ret) { 262f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen hid_err(hdev, "hw start failed\n"); 263f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return ret; 264f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 265f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 266f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen for (i = 0; i < GT683R_LED_COUNT; i++) { 267f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen name_sz = strlen(dev_name(&hdev->dev)) + 268f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen strlen(gt683r_panel_names[i]) + 3; 269f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 270f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen name = devm_kzalloc(&hdev->dev, name_sz, GFP_KERNEL); 271f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (!name) { 272f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen ret = -ENOMEM; 273f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen goto fail; 274f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 275f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 276f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen snprintf(name, name_sz, "%s::%s", 277f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen dev_name(&hdev->dev), gt683r_panel_names[i]); 278f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->led_devs[i].name = name; 279f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->led_devs[i].max_brightness = 1; 280f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led->led_devs[i].brightness_set = gt683r_brightness_set; 2816522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen led->led_devs[i].groups = gt683r_led_groups; 2826522fe1c39a79d4753e37d912876315720119f82Janne Kanniainen 283f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen ret = led_classdev_register(&hdev->dev, &led->led_devs[i]); 284f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen if (ret) { 285f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen hid_err(hdev, "could not register led device\n"); 286f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen goto fail; 287f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 288f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen } 289f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 290f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return 0; 291f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 292f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenfail: 293f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen for (i = i - 1; i >= 0; i--) 294f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led_classdev_unregister(&led->led_devs[i]); 295f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen hid_hw_stop(hdev); 296f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen return ret; 297f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 298f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 299f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic void gt683r_led_remove(struct hid_device *hdev) 300f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen{ 301f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen int i; 302f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen struct gt683r_led *led = hid_get_drvdata(hdev); 303f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 304f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen for (i = 0; i < GT683R_LED_COUNT; i++) 305f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen led_classdev_unregister(&led->led_devs[i]); 306f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen flush_work(&led->work); 307f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen hid_hw_stop(hdev); 308f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen} 309f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 310f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenstatic struct hid_driver gt683r_led_driver = { 311f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen .probe = gt683r_led_probe, 312f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen .remove = gt683r_led_remove, 313f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen .name = "gt683r_led", 314f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen .id_table = gt683r_led_id, 315f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen}; 316f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 317f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainenmodule_hid_driver(gt683r_led_driver); 318f471d9480275796dea2ac7ec249b050e70a2888dJanne Kanniainen 319f471d9480275796dea2ac7ec249b050e70a2888dJanne KanniainenMODULE_AUTHOR("Janne Kanniainen"); 320f471d9480275796dea2ac7ec249b050e70a2888dJanne KanniainenMODULE_DESCRIPTION("MSI GT683R led driver"); 321f471d9480275796dea2ac7ec249b050e70a2888dJanne KanniainenMODULE_LICENSE("GPL"); 322