162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * MEN 14F021P00 Board Management Controller (BMC) LEDs Driver. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This is the core LED driver of the MEN 14F021P00 BMC. 662306a36Sopenharmony_ci * There are four LEDs available which can be switched on and off. 762306a36Sopenharmony_ci * STATUS LED, HOT SWAP LED, USER LED 1, USER LED 2 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH 1062306a36Sopenharmony_ci */ 1162306a36Sopenharmony_ci 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/platform_device.h> 1562306a36Sopenharmony_ci#include <linux/leds.h> 1662306a36Sopenharmony_ci#include <linux/i2c.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#define BMC_CMD_LED_GET_SET 0xA0 1962306a36Sopenharmony_ci#define BMC_BIT_LED_STATUS BIT(0) 2062306a36Sopenharmony_ci#define BMC_BIT_LED_HOTSWAP BIT(1) 2162306a36Sopenharmony_ci#define BMC_BIT_LED_USER1 BIT(2) 2262306a36Sopenharmony_ci#define BMC_BIT_LED_USER2 BIT(3) 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_cistruct menf21bmc_led { 2562306a36Sopenharmony_ci struct led_classdev cdev; 2662306a36Sopenharmony_ci u8 led_bit; 2762306a36Sopenharmony_ci const char *name; 2862306a36Sopenharmony_ci struct i2c_client *i2c_client; 2962306a36Sopenharmony_ci}; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistatic struct menf21bmc_led leds[] = { 3262306a36Sopenharmony_ci { 3362306a36Sopenharmony_ci .name = "menf21bmc:led_status", 3462306a36Sopenharmony_ci .led_bit = BMC_BIT_LED_STATUS, 3562306a36Sopenharmony_ci }, 3662306a36Sopenharmony_ci { 3762306a36Sopenharmony_ci .name = "menf21bmc:led_hotswap", 3862306a36Sopenharmony_ci .led_bit = BMC_BIT_LED_HOTSWAP, 3962306a36Sopenharmony_ci }, 4062306a36Sopenharmony_ci { 4162306a36Sopenharmony_ci .name = "menf21bmc:led_user1", 4262306a36Sopenharmony_ci .led_bit = BMC_BIT_LED_USER1, 4362306a36Sopenharmony_ci }, 4462306a36Sopenharmony_ci { 4562306a36Sopenharmony_ci .name = "menf21bmc:led_user2", 4662306a36Sopenharmony_ci .led_bit = BMC_BIT_LED_USER2, 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci}; 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic DEFINE_MUTEX(led_lock); 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_cistatic void 5362306a36Sopenharmony_cimenf21bmc_led_set(struct led_classdev *led_cdev, enum led_brightness value) 5462306a36Sopenharmony_ci{ 5562306a36Sopenharmony_ci int led_val; 5662306a36Sopenharmony_ci struct menf21bmc_led *led = container_of(led_cdev, 5762306a36Sopenharmony_ci struct menf21bmc_led, cdev); 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci mutex_lock(&led_lock); 6062306a36Sopenharmony_ci led_val = i2c_smbus_read_byte_data(led->i2c_client, 6162306a36Sopenharmony_ci BMC_CMD_LED_GET_SET); 6262306a36Sopenharmony_ci if (led_val < 0) 6362306a36Sopenharmony_ci goto err_out; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci if (value == LED_OFF) 6662306a36Sopenharmony_ci led_val &= ~led->led_bit; 6762306a36Sopenharmony_ci else 6862306a36Sopenharmony_ci led_val |= led->led_bit; 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci i2c_smbus_write_byte_data(led->i2c_client, 7162306a36Sopenharmony_ci BMC_CMD_LED_GET_SET, led_val); 7262306a36Sopenharmony_cierr_out: 7362306a36Sopenharmony_ci mutex_unlock(&led_lock); 7462306a36Sopenharmony_ci} 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_cistatic int menf21bmc_led_probe(struct platform_device *pdev) 7762306a36Sopenharmony_ci{ 7862306a36Sopenharmony_ci int i; 7962306a36Sopenharmony_ci int ret; 8062306a36Sopenharmony_ci struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent); 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(leds); i++) { 8362306a36Sopenharmony_ci leds[i].cdev.name = leds[i].name; 8462306a36Sopenharmony_ci leds[i].cdev.brightness_set = menf21bmc_led_set; 8562306a36Sopenharmony_ci leds[i].i2c_client = i2c_client; 8662306a36Sopenharmony_ci ret = devm_led_classdev_register(&pdev->dev, &leds[i].cdev); 8762306a36Sopenharmony_ci if (ret < 0) { 8862306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to register LED device\n"); 8962306a36Sopenharmony_ci return ret; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci } 9262306a36Sopenharmony_ci dev_info(&pdev->dev, "MEN 140F21P00 BMC LED device enabled\n"); 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci return 0; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic struct platform_driver menf21bmc_led = { 9962306a36Sopenharmony_ci .probe = menf21bmc_led_probe, 10062306a36Sopenharmony_ci .driver = { 10162306a36Sopenharmony_ci .name = "menf21bmc_led", 10262306a36Sopenharmony_ci }, 10362306a36Sopenharmony_ci}; 10462306a36Sopenharmony_ci 10562306a36Sopenharmony_cimodule_platform_driver(menf21bmc_led); 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ciMODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>"); 10862306a36Sopenharmony_ciMODULE_DESCRIPTION("MEN 14F021P00 BMC led driver"); 10962306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 11062306a36Sopenharmony_ciMODULE_ALIAS("platform:menf21bmc_led"); 111