root/drivers/leds/leds-clevo-mail.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. clevo_mail_led_dmi_callback
  2. clevo_mail_led_set
  3. clevo_mail_led_blink
  4. clevo_mail_led_probe
  5. clevo_mail_led_remove
  6. clevo_mail_led_init
  7. clevo_mail_led_exit

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
   3 
   4 #include <linux/module.h>
   5 
   6 #include <linux/platform_device.h>
   7 #include <linux/err.h>
   8 #include <linux/leds.h>
   9 
  10 #include <linux/io.h>
  11 #include <linux/dmi.h>
  12 
  13 #include <linux/i8042.h>
  14 
  15 #define CLEVO_MAIL_LED_OFF              0x0084
  16 #define CLEVO_MAIL_LED_BLINK_1HZ        0x008A
  17 #define CLEVO_MAIL_LED_BLINK_0_5HZ      0x0083
  18 
  19 MODULE_AUTHOR("Márton Németh <nm127@freemail.hu>");
  20 MODULE_DESCRIPTION("Clevo mail LED driver");
  21 MODULE_LICENSE("GPL");
  22 
  23 static bool nodetect;
  24 module_param_named(nodetect, nodetect, bool, 0);
  25 MODULE_PARM_DESC(nodetect, "Skip DMI hardware detection");
  26 
  27 static struct platform_device *pdev;
  28 
  29 static int __init clevo_mail_led_dmi_callback(const struct dmi_system_id *id)
  30 {
  31         pr_info("'%s' found\n", id->ident);
  32         return 1;
  33 }
  34 
  35 /*
  36  * struct clevo_mail_led_dmi_table - List of known good models
  37  *
  38  * Contains the known good models this driver is compatible with.
  39  * When adding a new model try to be as strict as possible. This
  40  * makes it possible to keep the false positives (the model is
  41  * detected as working, but in reality it is not) as low as
  42  * possible.
  43  */
  44 static const struct dmi_system_id clevo_mail_led_dmi_table[] __initconst = {
  45         {
  46                 .callback = clevo_mail_led_dmi_callback,
  47                 .ident = "Clevo D410J",
  48                 .matches = {
  49                         DMI_MATCH(DMI_SYS_VENDOR, "VIA"),
  50                         DMI_MATCH(DMI_PRODUCT_NAME, "K8N800"),
  51                         DMI_MATCH(DMI_PRODUCT_VERSION, "VT8204B")
  52                 }
  53         },
  54         {
  55                 .callback = clevo_mail_led_dmi_callback,
  56                 .ident = "Clevo M5x0N",
  57                 .matches = {
  58                         DMI_MATCH(DMI_SYS_VENDOR, "CLEVO Co."),
  59                         DMI_MATCH(DMI_PRODUCT_NAME, "M5x0N")
  60                 }
  61         },
  62         {
  63                 .callback = clevo_mail_led_dmi_callback,
  64                 .ident = "Clevo M5x0V",
  65                 .matches = {
  66                         DMI_MATCH(DMI_BOARD_VENDOR, "CLEVO Co. "),
  67                         DMI_MATCH(DMI_BOARD_NAME, "M5X0V "),
  68                         DMI_MATCH(DMI_PRODUCT_VERSION, "VT6198")
  69                 }
  70         },
  71         {
  72                 .callback = clevo_mail_led_dmi_callback,
  73                 .ident = "Clevo D400P",
  74                 .matches = {
  75                         DMI_MATCH(DMI_BOARD_VENDOR, "Clevo"),
  76                         DMI_MATCH(DMI_BOARD_NAME, "D400P"),
  77                         DMI_MATCH(DMI_BOARD_VERSION, "Rev.A"),
  78                         DMI_MATCH(DMI_PRODUCT_VERSION, "0106")
  79                 }
  80         },
  81         {
  82                 .callback = clevo_mail_led_dmi_callback,
  83                 .ident = "Clevo D410V",
  84                 .matches = {
  85                         DMI_MATCH(DMI_BOARD_VENDOR, "Clevo, Co."),
  86                         DMI_MATCH(DMI_BOARD_NAME, "D400V/D470V"),
  87                         DMI_MATCH(DMI_BOARD_VERSION, "SS78B"),
  88                         DMI_MATCH(DMI_PRODUCT_VERSION, "Rev. A1")
  89                 }
  90         },
  91         { }
  92 };
  93 MODULE_DEVICE_TABLE(dmi, clevo_mail_led_dmi_table);
  94 
  95 static void clevo_mail_led_set(struct led_classdev *led_cdev,
  96                                 enum led_brightness value)
  97 {
  98         i8042_lock_chip();
  99 
 100         if (value == LED_OFF)
 101                 i8042_command(NULL, CLEVO_MAIL_LED_OFF);
 102         else if (value <= LED_HALF)
 103                 i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
 104         else
 105                 i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
 106 
 107         i8042_unlock_chip();
 108 
 109 }
 110 
 111 static int clevo_mail_led_blink(struct led_classdev *led_cdev,
 112                                 unsigned long *delay_on,
 113                                 unsigned long *delay_off)
 114 {
 115         int status = -EINVAL;
 116 
 117         i8042_lock_chip();
 118 
 119         if (*delay_on == 0 /* ms */ && *delay_off == 0 /* ms */) {
 120                 /* Special case: the leds subsystem requested us to
 121                  * chose one user friendly blinking of the LED, and
 122                  * start it. Let's blink the led slowly (0.5Hz).
 123                  */
 124                 *delay_on = 1000; /* ms */
 125                 *delay_off = 1000; /* ms */
 126                 i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
 127                 status = 0;
 128 
 129         } else if (*delay_on == 500 /* ms */ && *delay_off == 500 /* ms */) {
 130                 /* blink the led with 1Hz */
 131                 i8042_command(NULL, CLEVO_MAIL_LED_BLINK_1HZ);
 132                 status = 0;
 133 
 134         } else if (*delay_on == 1000 /* ms */ && *delay_off == 1000 /* ms */) {
 135                 /* blink the led with 0.5Hz */
 136                 i8042_command(NULL, CLEVO_MAIL_LED_BLINK_0_5HZ);
 137                 status = 0;
 138 
 139         } else {
 140                 pr_debug("clevo_mail_led_blink(..., %lu, %lu),"
 141                        " returning -EINVAL (unsupported)\n",
 142                        *delay_on, *delay_off);
 143         }
 144 
 145         i8042_unlock_chip();
 146 
 147         return status;
 148 }
 149 
 150 static struct led_classdev clevo_mail_led = {
 151         .name                   = "clevo::mail",
 152         .brightness_set         = clevo_mail_led_set,
 153         .blink_set              = clevo_mail_led_blink,
 154         .flags                  = LED_CORE_SUSPENDRESUME,
 155 };
 156 
 157 static int __init clevo_mail_led_probe(struct platform_device *pdev)
 158 {
 159         return led_classdev_register(&pdev->dev, &clevo_mail_led);
 160 }
 161 
 162 static int clevo_mail_led_remove(struct platform_device *pdev)
 163 {
 164         led_classdev_unregister(&clevo_mail_led);
 165         return 0;
 166 }
 167 
 168 static struct platform_driver clevo_mail_led_driver = {
 169         .remove         = clevo_mail_led_remove,
 170         .driver         = {
 171                 .name           = KBUILD_MODNAME,
 172         },
 173 };
 174 
 175 static int __init clevo_mail_led_init(void)
 176 {
 177         int error = 0;
 178         int count = 0;
 179 
 180         /* Check with the help of DMI if we are running on supported hardware */
 181         if (!nodetect) {
 182                 count = dmi_check_system(clevo_mail_led_dmi_table);
 183         } else {
 184                 count = 1;
 185                 pr_err("Skipping DMI detection. "
 186                        "If the driver works on your hardware please "
 187                        "report model and the output of dmidecode in tracker "
 188                        "at http://sourceforge.net/projects/clevo-mailled/\n");
 189         }
 190 
 191         if (!count)
 192                 return -ENODEV;
 193 
 194         pdev = platform_device_register_simple(KBUILD_MODNAME, -1, NULL, 0);
 195         if (!IS_ERR(pdev)) {
 196                 error = platform_driver_probe(&clevo_mail_led_driver,
 197                                               clevo_mail_led_probe);
 198                 if (error) {
 199                         pr_err("Can't probe platform driver\n");
 200                         platform_device_unregister(pdev);
 201                 }
 202         } else
 203                 error = PTR_ERR(pdev);
 204 
 205         return error;
 206 }
 207 
 208 static void __exit clevo_mail_led_exit(void)
 209 {
 210         platform_device_unregister(pdev);
 211         platform_driver_unregister(&clevo_mail_led_driver);
 212 
 213         clevo_mail_led_set(NULL, LED_OFF);
 214 }
 215 
 216 module_init(clevo_mail_led_init);
 217 module_exit(clevo_mail_led_exit);

/* [<][>][^][v][top][bottom][index][help] */