···11+Kernel driver menf21bmc_hwmon22+=============================33+44+Supported chips:55+ * MEN 14F021P0066+ Prefix: 'menf21bmc_hwmon'77+ Adresses scanned: -88+99+Author: Andreas Werner <andreas.werner@men.de>1010+1111+Description1212+-----------1313+1414+The menf21bmc is a Board Management Controller (BMC) which provides an I2C1515+interface to the host to access the features implemented in the BMC.1616+1717+This driver gives access to the voltage monitoring feature of the main1818+voltages of the board.1919+The voltage sensors are connected to the ADC inputs of the BMC which is2020+a PIC16F917 Mikrocontroller.2121+2222+Usage Notes2323+-----------2424+2525+This driver is part of the MFD driver named "menf21bmc" and does2626+not auto-detect devices.2727+You will have to instantiate the MFD driver explicitly.2828+Please see Documentation/i2c/instantiating-devices for2929+details.3030+3131+Sysfs entries3232+-------------3333+3434+The following attributes are supported. All attributes are read only3535+The Limits are read once by the driver.3636+3737+in0_input +3.3V input voltage3838+in1_input +5.0V input voltage3939+in2_input +12.0V input voltage4040+in3_input +5V Standby input voltage4141+in4_input VBAT (on board battery)4242+4343+in[0-4]_min Minimum voltage limit4444+in[0-4]_max Maximum voltage limit4545+4646+in0_label "MON_3_3V"4747+in1_label "MON_5V"4848+in2_label "MON_12V"4949+in3_label "5V_STANDBY"5050+in4_label "VBAT"
+10
drivers/hwmon/Kconfig
···839839 This driver can also be built as a module. If so, the module840840 will be called mcp3021.841841842842+config SENSORS_MENF21BMC_HWMON843843+ tristate "MEN 14F021P00 BMC Hardware Monitoring"844844+ depends on MFD_MENF21BMC845845+ help846846+ Say Y here to include support for the MEN 14F021P00 BMC847847+ hardware monitoring.848848+849849+ This driver can also be built as a module. If so the module850850+ will be called menf21bmc_hwmon.851851+842852config SENSORS_ADCXX843853 tristate "National Semiconductor ADCxxxSxxx"844854 depends on SPI_MASTER
···11+/*22+ * MEN 14F021P00 Board Management Controller (BMC) hwmon driver.33+ *44+ * This is the core hwmon driver of the MEN 14F021P00 BMC.55+ * The BMC monitors the board voltages which can be access with this66+ * driver through sysfs.77+ *88+ * Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH99+ *1010+ * This program is free software; you can redistribute it and/or modify it1111+ * under the terms of the GNU General Public License as published by the1212+ * Free Software Foundation; either version 2 of the License, or (at your1313+ * option) any later version.1414+ */1515+1616+#include <linux/module.h>1717+#include <linux/kernel.h>1818+#include <linux/platform_device.h>1919+#include <linux/hwmon.h>2020+#include <linux/hwmon-sysfs.h>2121+#include <linux/jiffies.h>2222+#include <linux/slab.h>2323+#include <linux/i2c.h>2424+2525+#define DRV_NAME "menf21bmc_hwmon"2626+2727+#define BMC_VOLT_COUNT 52828+#define MENF21BMC_V33 02929+#define MENF21BMC_V5 13030+#define MENF21BMC_V12 23131+#define MENF21BMC_V5_SB 33232+#define MENF21BMC_VBAT 43333+3434+#define IDX_TO_VOLT_MIN_CMD(idx) (0x40 + idx)3535+#define IDX_TO_VOLT_MAX_CMD(idx) (0x50 + idx)3636+#define IDX_TO_VOLT_INP_CMD(idx) (0x60 + idx)3737+3838+struct menf21bmc_hwmon {3939+ bool valid;4040+ struct i2c_client *i2c_client;4141+ unsigned long last_update;4242+ int in_val[BMC_VOLT_COUNT];4343+ int in_min[BMC_VOLT_COUNT];4444+ int in_max[BMC_VOLT_COUNT];4545+};4646+4747+static const char *const input_names[] = {4848+ [MENF21BMC_V33] = "MON_3_3V",4949+ [MENF21BMC_V5] = "MON_5V",5050+ [MENF21BMC_V12] = "MON_12V",5151+ [MENF21BMC_V5_SB] = "5V_STANDBY",5252+ [MENF21BMC_VBAT] = "VBAT"5353+};5454+5555+static struct menf21bmc_hwmon *menf21bmc_hwmon_update(struct device *dev)5656+{5757+ int i;5858+ int val;5959+ struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);6060+ struct menf21bmc_hwmon *data_ret = drv_data;6161+6262+ if (time_after(jiffies, drv_data->last_update + HZ)6363+ || !drv_data->valid) {6464+ for (i = 0; i < BMC_VOLT_COUNT; i++) {6565+ val = i2c_smbus_read_word_data(drv_data->i2c_client,6666+ IDX_TO_VOLT_INP_CMD(i));6767+ if (val < 0) {6868+ data_ret = ERR_PTR(val);6969+ goto abort;7070+ }7171+ drv_data->in_val[i] = val;7272+ }7373+ drv_data->last_update = jiffies;7474+ drv_data->valid = true;7575+ }7676+abort:7777+ return data_ret;7878+}7979+8080+static int menf21bmc_hwmon_get_volt_limits(struct menf21bmc_hwmon *drv_data)8181+{8282+ int i, val;8383+8484+ for (i = 0; i < BMC_VOLT_COUNT; i++) {8585+ val = i2c_smbus_read_word_data(drv_data->i2c_client,8686+ IDX_TO_VOLT_MIN_CMD(i));8787+ if (val < 0)8888+ return val;8989+9090+ drv_data->in_min[i] = val;9191+9292+ val = i2c_smbus_read_word_data(drv_data->i2c_client,9393+ IDX_TO_VOLT_MAX_CMD(i));9494+ if (val < 0)9595+ return val;9696+9797+ drv_data->in_max[i] = val;9898+ }9999+ return 0;100100+}101101+102102+static ssize_t103103+show_label(struct device *dev, struct device_attribute *devattr, char *buf)104104+{105105+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);106106+107107+ return sprintf(buf, "%s\n", input_names[attr->index]);108108+}109109+110110+static ssize_t111111+show_in(struct device *dev, struct device_attribute *devattr, char *buf)112112+{113113+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);114114+ struct menf21bmc_hwmon *drv_data = menf21bmc_hwmon_update(dev);115115+116116+ if (IS_ERR(drv_data))117117+ return PTR_ERR(drv_data);118118+119119+ return sprintf(buf, "%d\n", drv_data->in_val[attr->index]);120120+}121121+122122+static ssize_t123123+show_min(struct device *dev, struct device_attribute *devattr, char *buf)124124+{125125+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);126126+ struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);127127+128128+ return sprintf(buf, "%d\n", drv_data->in_min[attr->index]);129129+}130130+131131+static ssize_t132132+show_max(struct device *dev, struct device_attribute *devattr, char *buf)133133+{134134+ struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);135135+ struct menf21bmc_hwmon *drv_data = dev_get_drvdata(dev);136136+137137+ return sprintf(buf, "%d\n", drv_data->in_max[attr->index]);138138+}139139+140140+#define create_voltage_sysfs(idx) \141141+static SENSOR_DEVICE_ATTR(in##idx##_input, S_IRUGO, \142142+ show_in, NULL, idx); \143143+static SENSOR_DEVICE_ATTR(in##idx##_min, S_IRUGO, \144144+ show_min, NULL, idx); \145145+static SENSOR_DEVICE_ATTR(in##idx##_max, S_IRUGO, \146146+ show_max, NULL, idx); \147147+static SENSOR_DEVICE_ATTR(in##idx##_label, S_IRUGO, \148148+ show_label, NULL, idx);149149+150150+create_voltage_sysfs(0);151151+create_voltage_sysfs(1);152152+create_voltage_sysfs(2);153153+create_voltage_sysfs(3);154154+create_voltage_sysfs(4);155155+156156+static struct attribute *menf21bmc_hwmon_attrs[] = {157157+ &sensor_dev_attr_in0_input.dev_attr.attr,158158+ &sensor_dev_attr_in0_min.dev_attr.attr,159159+ &sensor_dev_attr_in0_max.dev_attr.attr,160160+ &sensor_dev_attr_in0_label.dev_attr.attr,161161+162162+ &sensor_dev_attr_in1_input.dev_attr.attr,163163+ &sensor_dev_attr_in1_min.dev_attr.attr,164164+ &sensor_dev_attr_in1_max.dev_attr.attr,165165+ &sensor_dev_attr_in1_label.dev_attr.attr,166166+167167+ &sensor_dev_attr_in2_input.dev_attr.attr,168168+ &sensor_dev_attr_in2_min.dev_attr.attr,169169+ &sensor_dev_attr_in2_max.dev_attr.attr,170170+ &sensor_dev_attr_in2_label.dev_attr.attr,171171+172172+ &sensor_dev_attr_in3_input.dev_attr.attr,173173+ &sensor_dev_attr_in3_min.dev_attr.attr,174174+ &sensor_dev_attr_in3_max.dev_attr.attr,175175+ &sensor_dev_attr_in3_label.dev_attr.attr,176176+177177+ &sensor_dev_attr_in4_input.dev_attr.attr,178178+ &sensor_dev_attr_in4_min.dev_attr.attr,179179+ &sensor_dev_attr_in4_max.dev_attr.attr,180180+ &sensor_dev_attr_in4_label.dev_attr.attr,181181+ NULL182182+};183183+184184+ATTRIBUTE_GROUPS(menf21bmc_hwmon);185185+186186+static int menf21bmc_hwmon_probe(struct platform_device *pdev)187187+{188188+ int ret;189189+ struct menf21bmc_hwmon *drv_data;190190+ struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);191191+ struct device *hwmon_dev;192192+193193+ drv_data = devm_kzalloc(&pdev->dev, sizeof(struct menf21bmc_hwmon),194194+ GFP_KERNEL);195195+ if (!drv_data)196196+ return -ENOMEM;197197+198198+ drv_data->i2c_client = i2c_client;199199+200200+ ret = menf21bmc_hwmon_get_volt_limits(drv_data);201201+ if (ret) {202202+ dev_err(&pdev->dev, "failed to read sensor limits");203203+ return ret;204204+ }205205+206206+ hwmon_dev = devm_hwmon_device_register_with_groups(&pdev->dev,207207+ "menf21bmc", drv_data,208208+ menf21bmc_hwmon_groups);209209+ if (IS_ERR(hwmon_dev))210210+ return PTR_ERR(hwmon_dev);211211+212212+ dev_info(&pdev->dev, "MEN 14F021P00 BMC hwmon device enabled");213213+214214+ return 0;215215+}216216+217217+static struct platform_driver menf21bmc_hwmon = {218218+ .probe = menf21bmc_hwmon_probe,219219+ .driver = {220220+ .name = DRV_NAME,221221+ .owner = THIS_MODULE,222222+ },223223+};224224+225225+module_platform_driver(menf21bmc_hwmon);226226+227227+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");228228+MODULE_DESCRIPTION("MEN 14F021P00 BMC hwmon");229229+MODULE_LICENSE("GPL v2");230230+MODULE_ALIAS("platform:menf21bmc_hwmon");
+9
drivers/leds/Kconfig
···468468 This option enables support for the LEDs on the Bachmann OT200.469469 Say Y to enable LEDs on the Bachmann OT200.470470471471+config LEDS_MENF21BMC472472+ tristate "LED support for the MEN 14F021P00 BMC"473473+ depends on LEDS_CLASS && MFD_MENF21BMC474474+ help475475+ Say Y here to include support for the MEN 14F021P00 BMC LEDs.476476+477477+ This driver can also be built as a module. If so the module478478+ will be called leds-menf21bmc.479479+471480comment "LED driver for blink(1) USB RGB LED is under Special HID drivers (HID_THINGM)"472481473482config LEDS_BLINKM
···11+/*22+ * MEN 14F021P00 Board Management Controller (BMC) LEDs Driver.33+ *44+ * This is the core LED driver of the MEN 14F021P00 BMC.55+ * There are four LEDs available which can be switched on and off.66+ * STATUS LED, HOT SWAP LED, USER LED 1, USER LED 277+ *88+ * Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH99+ *1010+ * This program is free software; you can redistribute it and/or modify it1111+ * under the terms of the GNU General Public License as published by the1212+ * Free Software Foundation; either version 2 of the License, or (at your1313+ * option) any later version.1414+ */1515+1616+#include <linux/module.h>1717+#include <linux/kernel.h>1818+#include <linux/platform_device.h>1919+#include <linux/leds.h>2020+#include <linux/i2c.h>2121+2222+#define BMC_CMD_LED_GET_SET 0xA02323+#define BMC_BIT_LED_STATUS BIT(0)2424+#define BMC_BIT_LED_HOTSWAP BIT(1)2525+#define BMC_BIT_LED_USER1 BIT(2)2626+#define BMC_BIT_LED_USER2 BIT(3)2727+2828+struct menf21bmc_led {2929+ struct led_classdev cdev;3030+ u8 led_bit;3131+ const char *name;3232+ struct i2c_client *i2c_client;3333+};3434+3535+static struct menf21bmc_led leds[] = {3636+ {3737+ .name = "menf21bmc:led_status",3838+ .led_bit = BMC_BIT_LED_STATUS,3939+ },4040+ {4141+ .name = "menf21bmc:led_hotswap",4242+ .led_bit = BMC_BIT_LED_HOTSWAP,4343+ },4444+ {4545+ .name = "menf21bmc:led_user1",4646+ .led_bit = BMC_BIT_LED_USER1,4747+ },4848+ {4949+ .name = "menf21bmc:led_user2",5050+ .led_bit = BMC_BIT_LED_USER2,5151+ }5252+};5353+5454+static DEFINE_MUTEX(led_lock);5555+5656+static void5757+menf21bmc_led_set(struct led_classdev *led_cdev, enum led_brightness value)5858+{5959+ int led_val;6060+ struct menf21bmc_led *led = container_of(led_cdev,6161+ struct menf21bmc_led, cdev);6262+6363+ mutex_lock(&led_lock);6464+ led_val = i2c_smbus_read_byte_data(led->i2c_client,6565+ BMC_CMD_LED_GET_SET);6666+ if (led_val < 0)6767+ goto err_out;6868+6969+ if (value == LED_OFF)7070+ led_val &= ~led->led_bit;7171+ else7272+ led_val |= led->led_bit;7373+7474+ i2c_smbus_write_byte_data(led->i2c_client,7575+ BMC_CMD_LED_GET_SET, led_val);7676+err_out:7777+ mutex_unlock(&led_lock);7878+}7979+8080+static int menf21bmc_led_probe(struct platform_device *pdev)8181+{8282+ int i;8383+ int ret;8484+ struct i2c_client *i2c_client = to_i2c_client(pdev->dev.parent);8585+8686+ for (i = 0; i < ARRAY_SIZE(leds); i++) {8787+ leds[i].cdev.name = leds[i].name;8888+ leds[i].cdev.brightness_set = menf21bmc_led_set;8989+ leds[i].i2c_client = i2c_client;9090+ ret = led_classdev_register(&pdev->dev, &leds[i].cdev);9191+ if (ret < 0)9292+ goto err_free_leds;9393+ }9494+ dev_info(&pdev->dev, "MEN 140F21P00 BMC LED device enabled\n");9595+9696+ return 0;9797+9898+err_free_leds:9999+ dev_err(&pdev->dev, "failed to register LED device\n");100100+101101+ for (i = i - 1; i >= 0; i--)102102+ led_classdev_unregister(&leds[i].cdev);103103+104104+ return ret;105105+}106106+107107+static int menf21bmc_led_remove(struct platform_device *pdev)108108+{109109+ int i;110110+111111+ for (i = 0; i < ARRAY_SIZE(leds); i++)112112+ led_classdev_unregister(&leds[i].cdev);113113+114114+ return 0;115115+}116116+117117+static struct platform_driver menf21bmc_led = {118118+ .probe = menf21bmc_led_probe,119119+ .remove = menf21bmc_led_remove,120120+ .driver = {121121+ .name = "menf21bmc_led",122122+ .owner = THIS_MODULE,123123+ },124124+};125125+126126+module_platform_driver(menf21bmc_led);127127+128128+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");129129+MODULE_DESCRIPTION("MEN 14F021P00 BMC led driver");130130+MODULE_LICENSE("GPL v2");131131+MODULE_ALIAS("platform:menf21bmc_led");
+15
drivers/mfd/Kconfig
···454454 additional drivers must be enabled in order to use the functionality455455 of the device.456456457457+config MFD_MENF21BMC458458+ tristate "MEN 14F021P00 Board Management Controller Support"459459+ depends on I2C460460+ select MFD_CORE461461+ help462462+ Say yes here to add support for the MEN 14F021P00 BMC463463+ which is a Board Management Controller connected to the I2C bus.464464+ The device supports multiple sub-devices like LED, HWMON and WDT.465465+ This driver provides common support for accessing the devices;466466+ additional drivers must be enabled in order to use the467467+ functionality of the BMC device.468468+469469+ This driver can also be built as a module. If so the module470470+ will be called menf21bmc.471471+457472config EZX_PCAP458473 bool "Motorola EZXPCAP Support"459474 depends on SPI_MASTER
···11+/*22+ * MEN 14F021P00 Board Management Controller (BMC) MFD Core Driver.33+ *44+ * Copyright (C) 2014 MEN Mikro Elektronik Nuernberg GmbH55+ *66+ * This program is free software; you can redistribute it and/or modify it77+ * under the terms of the GNU General Public License as published by the88+ * Free Software Foundation; either version 2 of the License, or (at your99+ * option) any later version.1010+ */1111+1212+#include <linux/kernel.h>1313+#include <linux/device.h>1414+#include <linux/module.h>1515+#include <linux/i2c.h>1616+#include <linux/mfd/core.h>1717+1818+#define BMC_CMD_WDT_EXIT_PROD 0x181919+#define BMC_CMD_WDT_PROD_STAT 0x192020+#define BMC_CMD_REV_MAJOR 0x802121+#define BMC_CMD_REV_MINOR 0x812222+#define BMC_CMD_REV_MAIN 0x822323+2424+static struct mfd_cell menf21bmc_cell[] = {2525+ { .name = "menf21bmc_wdt", },2626+ { .name = "menf21bmc_led", },2727+ { .name = "menf21bmc_hwmon", }2828+};2929+3030+static int menf21bmc_wdt_exit_prod_mode(struct i2c_client *client)3131+{3232+ int val, ret;3333+3434+ val = i2c_smbus_read_byte_data(client, BMC_CMD_WDT_PROD_STAT);3535+ if (val < 0)3636+ return val;3737+3838+ /*3939+ * Production mode should be not active after delivery of the Board.4040+ * To be sure we check it, inform the user and exit the mode4141+ * if active.4242+ */4343+ if (val == 0x00) {4444+ dev_info(&client->dev,4545+ "BMC in production mode. Exit production mode\n");4646+4747+ ret = i2c_smbus_write_byte(client, BMC_CMD_WDT_EXIT_PROD);4848+ if (ret < 0)4949+ return ret;5050+ }5151+5252+ return 0;5353+}5454+5555+static int5656+menf21bmc_probe(struct i2c_client *client, const struct i2c_device_id *ids)5757+{5858+ int rev_major, rev_minor, rev_main;5959+ int ret;6060+6161+ ret = i2c_check_functionality(client->adapter,6262+ I2C_FUNC_SMBUS_BYTE_DATA |6363+ I2C_FUNC_SMBUS_WORD_DATA |6464+ I2C_FUNC_SMBUS_BYTE);6565+ if (!ret)6666+ return -ENODEV;6767+6868+ rev_major = i2c_smbus_read_word_data(client, BMC_CMD_REV_MAJOR);6969+ if (rev_major < 0) {7070+ dev_err(&client->dev, "failed to get BMC major revision\n");7171+ return rev_major;7272+ }7373+7474+ rev_minor = i2c_smbus_read_word_data(client, BMC_CMD_REV_MINOR);7575+ if (rev_minor < 0) {7676+ dev_err(&client->dev, "failed to get BMC minor revision\n");7777+ return rev_minor;7878+ }7979+8080+ rev_main = i2c_smbus_read_word_data(client, BMC_CMD_REV_MAIN);8181+ if (rev_main < 0) {8282+ dev_err(&client->dev, "failed to get BMC main revision\n");8383+ return rev_main;8484+ }8585+8686+ dev_info(&client->dev, "FW Revision: %02d.%02d.%02d\n",8787+ rev_major, rev_minor, rev_main);8888+8989+ /*9090+ * We have to exit the Production Mode of the BMC to activate the9191+ * Watchdog functionality and the BIOS life sign monitoring.9292+ */9393+ ret = menf21bmc_wdt_exit_prod_mode(client);9494+ if (ret < 0) {9595+ dev_err(&client->dev, "failed to leave production mode\n");9696+ return ret;9797+ }9898+9999+ ret = mfd_add_devices(&client->dev, 0, menf21bmc_cell,100100+ ARRAY_SIZE(menf21bmc_cell), NULL, 0, NULL);101101+ if (ret < 0) {102102+ dev_err(&client->dev, "failed to add BMC sub-devices\n");103103+ return ret;104104+ }105105+106106+ return 0;107107+}108108+109109+static int menf21bmc_remove(struct i2c_client *client)110110+{111111+ mfd_remove_devices(&client->dev);112112+ return 0;113113+}114114+115115+static const struct i2c_device_id menf21bmc_id_table[] = {116116+ { "menf21bmc" },117117+ { }118118+};119119+MODULE_DEVICE_TABLE(i2c, menf21bmc_id_table);120120+121121+static struct i2c_driver menf21bmc_driver = {122122+ .driver.name = "menf21bmc",123123+ .id_table = menf21bmc_id_table,124124+ .probe = menf21bmc_probe,125125+ .remove = menf21bmc_remove,126126+};127127+128128+module_i2c_driver(menf21bmc_driver);129129+130130+MODULE_DESCRIPTION("MEN 14F021P00 BMC mfd core driver");131131+MODULE_AUTHOR("Andreas Werner <andreas.werner@men.de>");132132+MODULE_LICENSE("GPL v2");
+10
drivers/watchdog/Kconfig
···9595 If you say yes here you get support for watchdog device9696 controlled through GPIO-line.97979898+config MENF21BMC_WATCHDOG9999+ tristate "MEN 14F021P00 BMC Watchdog"100100+ depends on MFD_MENF21BMC101101+ select WATCHDOG_CORE102102+ help103103+ Say Y here to include support for the MEN 14F021P00 BMC Watchdog.104104+105105+ This driver can also be built as a module. If so the module106106+ will be called menf21bmc_wdt.107107+98108config WM831X_WATCHDOG99109 tristate "WM831x watchdog"100110 depends on MFD_WM831X