leds-menf21bmc.c 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * MEN 14F021P00 Board Management Controller (BMC) LEDs Driver.
  4. *
  5. * This is the core LED driver of the MEN 14F021P00 BMC.
  6. * There are four LEDs available which can be switched on and off.
  7. * STATUS LED, HOT SWAP LED, USER LED 1, USER LED 2
  8. *
  9. * Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH
  10. */
  11. #include <linux/module.h>
  12. #include <linux/kernel.h>
  13. #include <linux/platform_device.h>
  14. #include <linux/leds.h>
  15. #include <linux/i2c.h>
  16. #define BMC_CMD_LED_GET_SET 0xA0
  17. #define BMC_BIT_LED_STATUS BIT(0)
  18. #define BMC_BIT_LED_HOTSWAP BIT(1)
  19. #define BMC_BIT_LED_USER1 BIT(2)
  20. #define BMC_BIT_LED_USER2 BIT(3)
  21. struct menf21bmc_led {
  22. struct led_classdev cdev;
  23. u8 led_bit;
  24. const char *name;
  25. struct i2c_client *i2c_client;
  26. };
  27. static struct menf21bmc_led leds[] = {
  28. {
  29. .name = "menf21bmc:led_status",
  30. .led_bit = BMC_BIT_LED_STATUS,
  31. },
  32. {
  33. .name = "menf21bmc:led_hotswap",
  34. .led_bit = BMC_BIT_LED_HOTSWAP,
  35. },
  36. {
  37. .name = "menf21bmc:led_user1",
  38. .led_bit = BMC_BIT_LED_USER1,
  39. },
  40. {
  41. .name = "menf21bmc:led_user2",
  42. .led_bit = BMC_BIT_LED_USER2,
  43. }
  44. };
  45. static DEFINE_MUTEX(led_lock);
  46. static void
  47. menf21bmc_led_set(struct led_classdev *led_cdev, enum led_brightness value)
  48. {
  49. int led_val;
  50. struct menf21bmc_led *led = container_of(led_cdev,
  51. struct menf21bmc_led, cdev);
  52. mutex_lock(&led_lock);
  53. led_val = i2c_smbus_read_byte_data(led->i2c_client,
  54. BMC_CMD_LED_GET_SET);
  55. if (led_val < 0)
  56. goto err_out;
  57. if (value == LED_OFF)
  58. led_val &= ~led->led_bit;
  59. else
  60. led_val |= led->led_bit;
  61. i2c_smbus_write_byte_data(led->i2c_client,
  62. BMC_CMD_LED_GET_SET, led_val);
  63. err_out:
  64. mutex_unlock(&led_lock);
  65. }
  66. static int menf21bmc_led_probe(struct platform_device *pdev)
  67. {
  68. int i;
  69. int ret;
  70. struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);
  71. for (i = 0; i < ARRAY_SIZE(leds); i++) {
  72. leds[i].cdev.name = leds[i].name;
  73. leds[i].cdev.brightness_set = menf21bmc_led_set;
  74. leds[i].i2c_client = i2c_client;
  75. ret = devm_led_classdev_register(&pdev->dev, &leds[i].cdev);
  76. if (ret < 0) {
  77. dev_err(&pdev->dev, "failed to register LED device\n");
  78. return ret;
  79. }
  80. }
  81. dev_info(&pdev->dev, "MEN 140F21P00 BMC LED device enabled\n");
  82. return 0;
  83. }
  84. static struct platform_driver menf21bmc_led = {
  85. .probe = menf21bmc_led_probe,
  86. .driver = {
  87. .name = "menf21bmc_led",
  88. },
  89. };
  90. module_platform_driver(menf21bmc_led);
  91. MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");
  92. MODULE_DESCRIPTION("MEN 14F021P00 BMC led driver");
  93. MODULE_LICENSE("GPL v2");
  94. MODULE_ALIAS("platform:menf21bmc_led");