Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/807164/?format=api
{ "id": 807164, "url": "http://patchwork.ozlabs.org/api/patches/807164/?format=api", "web_url": "http://patchwork.ozlabs.org/project/devicetree-bindings/patch/1504029616-192277-2-git-send-email-vadimp@mellanox.com/", "project": { "id": 37, "url": "http://patchwork.ozlabs.org/api/projects/37/?format=api", "name": "Devicetree Bindings", "link_name": "devicetree-bindings", "list_id": "devicetree.vger.kernel.org", "list_email": "devicetree@vger.kernel.org", "web_url": "", "scm_url": "", "webscm_url": "", "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<1504029616-192277-2-git-send-email-vadimp@mellanox.com>", "list_archive_url": null, "date": "2017-08-29T18:00:15", "name": "[v4,1/2] mfd: Add Mellanox regmap core driver", "commit_ref": null, "pull_url": null, "state": "changes-requested", "archived": true, "hash": "5dd9c9cfb46f7e29a39807c859e697d0a23e977d", "submitter": { "id": 69757, "url": "http://patchwork.ozlabs.org/api/people/69757/?format=api", "name": "Vadim Pasternak", "email": "vadimp@mellanox.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/devicetree-bindings/patch/1504029616-192277-2-git-send-email-vadimp@mellanox.com/mbox/", "series": [ { "id": 401, "url": "http://patchwork.ozlabs.org/api/series/401/?format=api", "web_url": "http://patchwork.ozlabs.org/project/devicetree-bindings/list/?series=401", "date": "2017-08-29T18:00:14", "name": "Introduce support for mlxreg mfd core and I2C drivers", "version": 4, "mbox": "http://patchwork.ozlabs.org/series/401/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/807164/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/807164/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "<devicetree-owner@vger.kernel.org>", "X-Original-To": "incoming-dt@patchwork.ozlabs.org", "Delivered-To": "patchwork-incoming-dt@bilbo.ozlabs.org", "Authentication-Results": "ozlabs.org;\n\tspf=none (mailfrom) smtp.mailfrom=vger.kernel.org\n\t(client-ip=209.132.180.67; helo=vger.kernel.org;\n\tenvelope-from=devicetree-owner@vger.kernel.org; receiver=<UNKNOWN>)", "Received": [ "from vger.kernel.org (vger.kernel.org [209.132.180.67])\n\tby ozlabs.org (Postfix) with ESMTP id 3xhYMW1c6rz9s7f\n\tfor <incoming-dt@patchwork.ozlabs.org>;\n\tWed, 30 Aug 2017 02:03:19 +1000 (AEST)", "(majordomo@vger.kernel.org) by vger.kernel.org via listexpand\n\tid S1752561AbdH2QDS (ORCPT\n\t<rfc822;incoming-dt@patchwork.ozlabs.org>);\n\tTue, 29 Aug 2017 12:03:18 -0400", "from mail-il-dmz.mellanox.com ([193.47.165.129]:54556 \"EHLO\n\tmellanox.co.il\" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org\n\twith ESMTP id S1753420AbdH2QDP (ORCPT\n\t<rfc822; devicetree@vger.kernel.org>); Tue, 29 Aug 2017 12:03:15 -0400", "from Internal Mail-Server by MTLPINE1 (envelope-from\n\tvadimp@mellanox.com)\n\twith ESMTPS (AES256-SHA encrypted); 29 Aug 2017 19:03:11 +0300", "from r-mgtswh-226.mtr.labs.mlnx. (r-mgtswh-226.mtr.labs.mlnx\n\t[10.209.1.51])\n\tby labmailer.mlnx (8.13.8/8.13.8) with ESMTP id v7TG39bP021485;\n\tTue, 29 Aug 2017 19:03:11 +0300" ], "From": "Vadim Pasternak <vadimp@mellanox.com>", "To": "lee.jones@linaro.org, robh+dt@kernel.org, pavel@ucw.cz", "Cc": "devicetree@vger.kernel.org, j.anaszewski@samsung.com,\n\trpurdie@rpsys.net, linux-leds@vger.kernel.org, jiri@resnulli.us,\n\tgregkh@linuxfoundation.org, platform-driver-x86@vger.kernel.org,\n\tVadim Pasternak <vadimp@mellanox.com>", "Subject": "[patch v4 1/2] mfd: Add Mellanox regmap core driver", "Date": "Tue, 29 Aug 2017 18:00:15 +0000", "Message-Id": "<1504029616-192277-2-git-send-email-vadimp@mellanox.com>", "X-Mailer": "git-send-email 2.1.4", "In-Reply-To": "<1504029616-192277-1-git-send-email-vadimp@mellanox.com>", "References": "<1504029616-192277-1-git-send-email-vadimp@mellanox.com>", "Sender": "devicetree-owner@vger.kernel.org", "Precedence": "bulk", "List-ID": "<devicetree.vger.kernel.org>", "X-Mailing-List": "devicetree@vger.kernel.org" }, "content": "This patch adds core regmap platform driver for Mellanox BMC cards with\nthe programmable devices based chassis control. The device logics,\ncontrolled by software includes:\n- Interrupt handling for chassis, ASIC, CPU events;\n- LED handling;\n- Exposes through sysfs mux, reset signals, reset cause notification;\nThe patch provides support for the access to programmable device through\nthe register map and allows dynamic device tree manipulation at runtime\nfor removable devices.\n\nThis driver requires activator driver, which responsibility is to create\nregister map and pass it to regmap core. Such activator could be based for\nexample on I2C, SPI or MMIO interface.\n\nDrivers exposes the number of hwmon attributes to sysfs according to the\nattribute groups, defined in the device tree. These attributes will be\nlocated for example in /sys/class/hwmon/hwmonX folder, which is a symbolic\nlink to for example:\n/sys/bus/i2c/devices/4-0072/mlxreg-core.1138/hwmon/hwmon10.\nThe attributes are divided to the groups, like in the below example:\n MUX nodes\n - safe_bios_disable\n - spi_burn_bios_ci\n - spi_burn_ncsi\n - uart_sel\n Reset nodes:\n - sys_power_cycle\n - bmc_upgrade\n - asic_reset\n Cause of reset nodes:\n - cpu_kernel_panic\n - cpu_shutdown\n - bmc_warm_reset\n General purpose RW nodes:\n - version\n\nDrivers also probes LED and hotplug drivers, in case device tree\ndescription contains LED and hotplug nodes.\n\nSigned-off-by: Vadim Pasternak <vadimp@mellanox.com>\n---\nv3->v4:\n Comments pointed out by Lee:\n - Split interrupt related logic into separate module and place this logic\n within the existing Mellanox hotplug driver. Move for this reason this\n driver from drivers/platform/x86 to drivers/platform/mellanox folder;\n Comments pointed out by Rob:\n - Make a separate patch /devicetree/bindings/vendor-prefixes.txt;\n - Add .txt to Documentation/devicetree/bindings/mfd/mellanox,mlxreg-core\n and send it within this series;\n - Modify \"compatible\" property;\n - Modify explanation for \"deferred\" property;\n - Describe each subnode by its own section;\n - Don't use underscore in attribute names;\n Changes added by Vadim:\n - Add mlxreg_hotplug_device and mlxreg_core_item structures to mlxreg.h\n and modify mlxreg_core_led_platform_data structure;\nv2->v3:\n Changes added by Vadim:\n - Change name of field led data in struct mlxreg_core_led_platform_data\n in mlxreg.h;\n - fix data position assignment in mlxreg_core_get;\n - update name of field led data in mlxreg_core_set_led;\nv1->v2:\n Comments pointed out by Pavel:\n - Remove extra new line in mellanox,mlxreg-core;\n - Replace three NOT with one in mlxreg_core_attr_show;\n - Make error message in mlxreg_core_work_helper shorter;\n - Make attribute assignment more readable;\n - Separate mellanox,mlxreg-core file for sending to DT maintainers.\n Comments pointed out by Jacek:\n - Since brightness_set_blocking is used instead of\n brightness_set, three fields from mlxreg_core_led_data are removed.\n---\n .../bindings/mfd/mellanox,mlxreg-core.txt | 367 +++++++++\n MAINTAINERS | 7 +\n drivers/mfd/Kconfig | 15 +\n drivers/mfd/Makefile | 1 +\n drivers/mfd/mlxreg-core.c | 839 +++++++++++++++++++++\n include/linux/platform_data/mlxreg.h | 138 ++++\n 6 files changed, 1367 insertions(+)\n create mode 100644 Documentation/devicetree/bindings/mfd/mellanox,mlxreg-core.txt\n create mode 100644 drivers/mfd/mlxreg-core.c\n create mode 100644 include/linux/platform_data/mlxreg.h", "diff": "diff --git a/Documentation/devicetree/bindings/mfd/mellanox,mlxreg-core.txt b/Documentation/devicetree/bindings/mfd/mellanox,mlxreg-core.txt\nnew file mode 100644\nindex 0000000..f8c776a\n--- /dev/null\n+++ b/Documentation/devicetree/bindings/mfd/mellanox,mlxreg-core.txt\n@@ -0,0 +1,367 @@\n+Mellanox programmable device control.\n+-------------------------------------\n+This binding defines the device control interface over I2C bus for Mellanox BMC\n+based switches.\n+\n+Required properties:\n+- compatible = \"mellanox,mlxreg-i2c\" or\n+\t\t\"mellanox,mlxreg-i2c-16\"\n+\n+- #address-cells : must be 1;\n+- #size-cells : must be 0;\n+- reg : I2C address;\n+\n+Optional properties:\n+- interrupt-parent : phandle of parent interrupt controller;\n+- interrupts : interrupt line;\n+- deferred : I2C deferred bus phandle;\n+\t I2C bus activation order enforce for the cases when hot-plug\n+\t devices are attached to I2C bus, which is initialized after the\n+\t I2C bus, where programmable device is attached;\n+- cell : top aggregation register offset;\n+- mask : top aggregation register mask;\n+\n+Optional nodes and their properties:\n+ - psu : power supply unit nodes:\n+\tRequired properties:\n+\t- aggr : effective bit in aggregation mask;\n+\t- reg : register offset for all group members;\n+\t- mask : register mask;\n+\t- phandles - list of relevant device nodes;\n+ - fan : fan unit nodes:\n+\tRequired properties:\n+\t- aggr : effective bit in aggregation mask;\n+\t- reg : register offset for all group members;\n+\t- mask : register mask;\n+\t- phandles - list of relevant device nodes;\n+ - pwr : power cable nodes:\n+\tRequired properties:\n+\t- aggr : effective bit in aggregation mask;\n+\t- reg : register offset for all group members;\n+\t- mask : register mask;\n+\t- phandles : list of relevant device nodes;\n+ - host : host side nodes (CPU host side for BMC):\n+\tRequired properties:\n+\t- aggr : effective bit in aggregation mask;\n+\t- reg : register offset for all group members;\n+\t- mask : register mask;\n+\t- phandles : list of relevant device nodes;\n+ - asic : asic nodes:\n+\tRequired properties:\n+\t- aggr : effective bit in aggregation mask;\n+\t- regs : register offsets array per group member;\n+\t- masks : register masks array per group member;\n+\t- phandles : list of relevant device nodes;\n+ - reset : reset nodes:\n+\tRequired properties:\n+\t- #address-cells : must be 1;\n+\t- #size-cells : must be 0;\n+\t- reset control subnodes:\n+\t\tRequired properties:\n+\t\t- reg : register offset;\n+\t\t- mask : attribute mask;\n+ - cause - reset cause nodes:\n+\tRequired properties:\n+\t- #address-cells : must be 1;\n+\t- #size-cells : must be 0;\n+\t- cause info subnodes:\n+\t\tRequired properties:\n+\t\t- reg : register offset;\n+\t\t- mask : attribute mask;\n+ - mux - mux nodes:\n+\tRequired properties:\n+\t- #address-cells : must be 1;\n+\t- #size-cells : must be 0;\n+\t- mux control subnodes:\n+\t\tRequired properties:\n+\t\t- reg : register offset;\n+\t\t- mask : attribute mask;\n+\t\t- bit : effective bit;\n+\tOptional property:\n+\t\t- phandles : relevant device node;\n+ - gprw - general purpose register nodes:\n+\tRequired properties:\n+\t- #address-cells : must be 1;\n+\t- #size-cells : must be 0;\n+\t- general purpose read-write register subnodes:\n+\t\tRequired properties:\n+\t\t- reg : register offset;\n+\t\t- mask : attribute mask;\n+ - gpro - general purpose register nodes:\n+\tRequired properties:\n+\t- #address-cells : must be 1;\n+\t- #size-cells : must be 0;\n+\t- general purpose read only register subnodes:\n+\t\tRequired properties:\n+\t\t- reg : register offset.\n+\t\t- mask : attribute mask.\n+ - led - led nodes:\n+\tRequired properties:\n+\t- #address-cells : must be 1;\n+\t- #size-cells : must be 0;\n+\t- led control nodes:\n+\t\tRequired properties:\n+\t\t- label : symbolic name;\n+\t\t- reg : register offset;\n+\t\t- mask : attribute mask;\n+\n+Example:\n+\tmlxcpld-mng-ctrl@71 {\n+\t\t#address-cells = <1>;\n+\t\t#size-cells = <0>;\n+\t\tinterrupt-parent = <&gpio>;\n+\t\tinterrupts = <ASPEED_GPIO(S, 1) 2>;\n+\t\tcompatible = \"mellanox,mlxcpld-ctrl-i2c\";\n+\t\treg = <0x71>;\n+\t\tdeferred = <&i2c6>;\n+\t\tcell = <0x3a>;\n+\t\tmask = <0x4c>;\n+\n+\t\tpsu {\n+\t\t\taggr = <0x08>;\n+\t\t\treg = <0x58>;\n+\t\t\tmask = <0x03>;\n+\t\t\tphandles = <&psu1_eeprom &psu2_eeprom>;\n+\t\t};\n+\n+\t\tpwr {\n+\t\t\taggr = <0x08>;\n+\t\t\treg = <0x64>;\n+\t\t\tmask = <0x03>;\n+\t\t\tphandles = <&psu1_ctrl &psu2_ctrl>;\n+\t\t};\n+\n+\t\tfan {\n+\t\t\taggr = <0x40>;\n+\t\t\treg = <0x88>;\n+\t\t\tmask = <0x0f>;\n+\t\t\tphandles = <&fan1_eeprom &fan2_eeprom &fan3_eeprom\n+\t\t\t\t &fan4_eeprom>;\n+\t\t};\n+\n+\t\tmux {\n+\t\t\t#address-cells = <1>;\n+\t\t\t#size-cells = <0>;\n+\n+\t\t\tuart_sel {\n+\t\t\t\treg = <0x30>;\n+\t\t\t\tmask = <0xef>;\n+\t\t\t\tbit = <0x00>;\n+\t\t\t};\n+\t\t\tspi_burn_bios_ci {\n+\t\t\t\treg = <0x32>;\n+\t\t\t\tmask = <0xfe>;\n+\t\t\t\tbit = <0x00>;\n+\t\t\t\tphandles = <&spi2>;\n+\t\t\t};\n+\t\t\tspi_burn_ncsi {\n+\t\t\t\treg = <0x32>;\n+\t\t\t\tmask = <0xfd>;\n+\t\t\t\tbit = <0x00>;\n+\t\t\t\tphandles = <&spi2>;\n+\t\t\t};\n+\t\t\tbmc_uart_en {\n+\t\t\t\treg = <0x32>;\n+\t\t\t\tmask = <0xdf>;\n+\t\t\t\tbit = <0x00>;\n+\t\t\t};\n+\t\t\tsafe_bios1 {\n+\t\t\t\treg = <0x35>;\n+\t\t\t\tmask = <0xfb>;\n+\t\t\t\tbit = <0x01>;\n+\t\t\t};\n+\t\t\tsafe_bios2 {\n+\t\t\t\treg = <0x35>;\n+\t\t\t\tmask = <0xf7>;\n+\t\t\t\tbit = <0x01>;\n+\t\t\t};\n+\t\t\tsafe_bios_disable {\n+\t\t\t\treg = <0x35>;\n+\t\t\t\tmask = <0xdf>;\n+\t\t\t\tbit = <0x01>;\n+\t\t\t};\n+\t\t};\n+\n+\t\tled {\n+\t\t\t#address-cells = <1>;\n+\t\t\t#size-cells = <0>;\n+\t\t\tstatus-green {\n+\t\t\t\treg = <0x20>;\n+\t\t\t\tmask = <0xf0>;\n+\t\t\t};\n+\t\t\tstatus-red {\n+\t\t\t\treg = <0x20>;\n+\t\t\t\tmask = <0xf0>;\n+\t\t\t};\n+\t\t\tstatus-amber {\n+\t\t\t\treg = <0x20>;\n+\t\t\t\tmask = <0xf0>;\n+\t\t\t};\n+\t\t\tfan1-green {\n+\t\t\t\treg = <0x21>;\n+\t\t\t\tmask = <0xf0>;\n+\t\t\t};\n+\t\t\tfan1-red {\n+\t\t\t\treg = <0x21>;\n+\t\t\t\tmask = <0xf0>;\n+\t\t\t};\n+\t\t\tfan2-green {\n+\t\t\t\treg = <0x21>;\n+\t\t\t\tmask = <0x0f>;\n+\t\t\t};\n+\t\t\tfan2-red {\n+\t\t\t\treg = <0x21>;\n+\t\t\t\tmask = <0x0f>;\n+\t\t\t};\n+\t\t\tfan3-green {\n+\t\t\t\treg = <0x22>;\n+\t\t\t\tmask = <0xf0>;\n+\t\t\t};\n+\t\t\tfan3-red {\n+\t\t\t\tlabel = \"fan3:red\";\n+\t\t\t\treg = <0x22>;\n+\t\t\t\tmask = <0xf0>;\n+\t\t\t};\n+\t\t\tfan4-green {\n+\t\t\t\treg = <0x22>;\n+\t\t\t\tmask = <0x0f>;\n+\t\t\t};\n+\t\t\tfan4-red {\n+\t\t\t\treg = <0x22>;\n+\t\t\t\tmask = <0x0f>;\n+\t\t\t};\n+\t\t};\n+\n+\t\treset {\n+\t\t\t#address-cells = <1>;\n+\t\t\t#size-cells = <0>;\n+\t\t\tbmc_reset_soft {\n+\t\t\t\treg = <0x17>;\n+\t\t\t\tmask = <0xfd>;\n+\t\t\t};\n+\t\t\tsystem_reset_hard {\n+\t\t\t\treg = <0x17>;\n+\t\t\t\tmask = <0xfe>;\n+\t\t\t};\n+\t\t\tcpu_reset_soft {\n+\t\t\t\treg = <0x17>;\n+\t\t\t\tmask = <0xf7>;\n+\t\t\t};\n+\t\t\tps1_on {\n+\t\t\t\treg = <0x30>;\n+\t\t\t\tmask = <0xfe>;\n+\t\t\t};\n+\t\t\tps2_on {\n+\t\t\t\tlabel = \"ps2_on\";\n+\t\t\t\treg = <0x30>;\n+\t\t\t\tmask = <0xfd>;\n+\t\t\t};\n+\t\t\tsys_power_cycle {\n+\t\t\t\treg = <0x30>;\n+\t\t\t\tmask = <0xfb>;\n+\t\t\t};\n+\t\t\tmng_pg_ovrd {\n+\t\t\t\treg = <0x30>;\n+\t\t\t\tmask = <0xf7>;\n+\t\t\t};\n+\t\t\tcpu_reset_hard {\n+\t\t\t\treg = <0x30>;\n+\t\t\t\tmask = <0xdf>;\n+\t\t\t};\n+\t\t};\n+\n+\t\tcause {\n+\t\t\t#address-cells = <1>;\n+\t\t\t#size-cells = <0>;\n+\t\t\tac_power_cycle {\n+\t\t\t\treg = <0x1d>;\n+\t\t\t\tmask = <0xfe>;\n+\t\t\t};\n+\t\t\tdc_power_cycle {\n+\t\t\t\treg = <0x1d>;\n+\t\t\t\tmask = <0xfd>;\n+\t\t\t};\n+\t\t\tcpu_power_down {\n+\t\t\t\treg = <0x1d>;\n+\t\t\t\tmask = <0xfb>;\n+\t\t\t};\n+\t\t\tcpu_reboot {\n+\t\t\t\treg = <0x1d>;\n+\t\t\t\tmask = <0xf7>;\n+\t\t\t};\n+\t\t\tcpu_shutdown {\n+\t\t\t\treg = <0x1d>;\n+\t\t\t\tmask = <0xef>;\n+\t\t\t};\n+\t\t\tcpu_watchdog {\n+\t\t\t\treg = <0x1d>;\n+\t\t\t\tmask = <0xef>;\n+\t\t\t};\n+\t\t\tcpu_kernel_panic {\n+\t\t\t\treg = <0x1d>;\n+\t\t\t\tmask = <0xef>;\n+\t\t\t};\n+\t\t\tbmc_warm_reset {\n+\t\t\t\treg = <0x71>;\n+\t\t\t\tmask = <0xfe>;\n+\t\t\t};\n+\t\t\tbmc_upgrade {\n+\t\t\t\treg = <0x2e>;\n+\t\t\t\tmask = <0xf7>;\n+\t\t\t};\n+\t\t};\n+\n+\t\tgpro {\n+\t\t\t#address-cells = <1>;\n+\t\t\t#size-cells = <0>;\n+\t\t\tversion {\n+\t\t\t\treg = <0x00>;\n+\t\t\t\tmask = <0xff>;\n+\t\t\t\tbit = <0xff>;\n+\t\t\t};\n+\t\t};\n+\t};\n+\n+\tmlxcpld-swb-ctrl@72 {\n+\t\t#address-cells = <1>;\n+\t\t#size-cells = <0>;\n+\t\tinterrupt-parent = <&gpio>;\n+\t\tinterrupts = <ASPEED_GPIO(S, 1) 2>;\n+\t\tcompatible = \"mellanox,mlxcpld-ctrl-i2c\";\n+\t\treg = <0x72>;\n+\t\tdeferred = <&i2c12>;\n+\t\tcell = <0x40>;\n+\t\tmask = <0x01>;\n+\n+\t\tasic {\n+\t\t\taggr = <0x01>;\n+\t\t\tregs = <0x50>;\n+\t\t\tmasks = <0x03>;\n+\t\t\tphandles = <&asic_thermal>;\n+\t\t};\n+\n+\t\tgpro {\n+\t\t\t#address-cells = <1>;\n+\t\t\t#size-cells = <0>;\n+\t\t\tversion {\n+\t\t\t\treg = <0x01>;\n+\t\t\t\tmask = <0xff>;\n+\t\t\t\tbit = <0xff>;\n+\t\t\t};\n+\t\t};\n+\n+\t\treset {\n+\t\t\t#address-cells = <1>;\n+\t\t\t#size-cells = <0>;\n+\n+\t\t\tasic_reset {\n+\t\t\t\treg = <0x19>;\n+\t\t\t\tmask = <0xf7>;\n+\t\t\t};\n+\t\t\tphy_reset {\n+\t\t\t\treg = <0x19>;\n+\t\t\t\tmask = <0xef>;\n+\t\t\t};\n+\t\t};\n+\n+\t};\ndiff --git a/MAINTAINERS b/MAINTAINERS\nindex 767e9d2..bcb7f45 100644\n--- a/MAINTAINERS\n+++ b/MAINTAINERS\n@@ -8294,6 +8294,13 @@ S:\tSupported\n F:\tdrivers/input/touchscreen/melfas_mip4.c\n F:\tDocumentation/devicetree/bindings/input/touchscreen/melfas_mip4.txt\n \n+MELLANOX BMC MFD DRIVERS\n+M:\tVadim Pasternak <vadimp@mellanox.com>\n+S:\tSupported\n+F:\tDocumentation/devicetree/bindings/mfd/mellanox,mlxreg-core.txt\n+F:\tdrivers/mfd/mlxreg-core.c\n+F:\tinclude/linux/platform_data/mlxreg.h\n+\n MELLANOX ETHERNET DRIVER (mlx4_en)\n M:\tTariq Toukan <tariqt@mellanox.com>\n L:\tnetdev@vger.kernel.org\ndiff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig\nindex 3eb5c93..fa1562f 100644\n--- a/drivers/mfd/Kconfig\n+++ b/drivers/mfd/Kconfig\n@@ -1694,6 +1694,21 @@ config MFD_STM32_TIMERS\n \t for PWM and IIO Timer. This driver allow to share the\n \t registers between the others drivers.\n \n+config MFD_MLXREG_CORE\n+\ttristate \"Mellanox programmable device register control for BMC\"\n+\tdepends on OF || COMPILE_TEST\n+\tdepends on REGMAP\n+\tdepends on OF_DYNAMIC\n+\thelp\n+\t Support for the Mellanox BMC card with hardware control by a\n+\t programmable device which includes signal handling for chassis,\n+\t ASIC, CPU events, LED control, exposing sysfs interface for\n+\t reset control, reset monitoring and mux selection for the access\n+\t to remote devices at the host side.\n+\n+\t This driver can also be built as a module. If so the module\n+\t will be called mlxreg-core.\n+\n menu \"Multimedia Capabilities Port drivers\"\n \tdepends on ARCH_SA1100\n \ndiff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile\nindex c16bf1e..9661ee2 100644\n--- a/drivers/mfd/Makefile\n+++ b/drivers/mfd/Makefile\n@@ -221,3 +221,4 @@ obj-$(CONFIG_MFD_SUN4I_GPADC)\t+= sun4i-gpadc.o\n \n obj-$(CONFIG_MFD_STM32_TIMERS) \t+= stm32-timers.o\n obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o\n+obj-$(CONFIG_MFD_MLXREG_CORE)\t+= mlxreg-core.o\ndiff --git a/drivers/mfd/mlxreg-core.c b/drivers/mfd/mlxreg-core.c\nnew file mode 100644\nindex 0000000..5060605\n--- /dev/null\n+++ b/drivers/mfd/mlxreg-core.c\n@@ -0,0 +1,839 @@\n+/*\n+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.\n+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ *\n+ * 1. Redistributions of source code must retain the above copyright\n+ * notice, this list of conditions and the following disclaimer.\n+ * 2. Redistributions in binary form must reproduce the above copyright\n+ * notice, this list of conditions and the following disclaimer in the\n+ * documentation and/or other materials provided with the distribution.\n+ * 3. Neither the names of the copyright holders nor the names of its\n+ * contributors may be used to endorse or promote products derived from\n+ * this software without specific prior written permission.\n+ *\n+ * Alternatively, this software may be distributed under the terms of the\n+ * GNU General Public License (\"GPL\") version 2 as published by the Free\n+ * Software Foundation.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n+ * POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#include <linux/device.h>\n+#include <linux/hwmon.h>\n+#include <linux/hwmon-sysfs.h>\n+#include <linux/leds.h>\n+#include <linux/module.h>\n+#include <linux/of_device.h>\n+#include <linux/platform_data/mlxreg.h>\n+#include <linux/platform_device.h>\n+#include <linux/regmap.h>\n+\n+/* Attribute parameters. */\n+#define MLXREG_CORE_ATTR_VALUE_SIZE\t10\n+#define MLXREG_CORE_ATTR_GROUP_NUM\t11\n+#define MLXREG_CORE_ATTRS_NUM\t\t48\n+\n+#define MLXREG_CORE_PROP_OKAY\t\t\"okay\"\n+#define MLXREG_CORE_PROP_DISABLED\t\"disabled\"\n+#define MLXREG_CORE_PROP_STATUS\t\t\"status\"\n+\n+/**\n+ * enum mlxreg_core_attr_type - sysfs attributes for hotplug events:\n+ *\n+ * @MLXREG_CORE_ATTR_PSU: power supply unit attribute;\n+ * @MLXREG_CORE_ATTR_PWR: power cable attribute;\n+ * @MLXREG_CORE_ATTR_FAN: FAN drawer attribute;\n+ * @MLXREG_CORE_ATTR_RST: reset attribute;\n+ * @MLXREG_CORE_ATTR_CAUSE: reset cause attribute;\n+ * @MLXREG_CORE_ATTR_MUX: mux attribute;\n+ * @MLXREG_CORE_ATTR_GPRW: general purpose read/write attribute;\n+ * @MLXREG_CORE_ATTR_GPRO: general purpose read only attribute;\n+ * @MLXREG_CORE_ATTR_LED: LED attribute;\n+ * @MLXREG_CORE_ATTR_HOST: host cpu attribute;\n+ */\n+enum mlxreg_core_attr_type {\n+\tMLXREG_CORE_ATTR_PSU,\n+\tMLXREG_CORE_ATTR_PWR,\n+\tMLXREG_CORE_ATTR_FAN,\n+\tMLXREG_CORE_ATTR_RST,\n+\tMLXREG_CORE_ATTR_CAUSE,\n+\tMLXREG_CORE_ATTR_MUX,\n+\tMLXREG_CORE_ATTR_GPRW,\n+\tMLXREG_CORE_ATTR_GPRO,\n+\tMLXREG_CORE_ATTR_ASIC,\n+\tMLXREG_CORE_ATTR_LED,\n+\tMLXREG_CORE_ATTR_HOST,\n+};\n+\n+/**\n+ * typedef mlxreg_core_parse_np - parse device node parameters.\n+ */\n+typedef int (*mlxreg_core_parse_np)(struct device_node *np,\n+\t\t\t\t struct device *dev,\n+\t\t\t\t struct mlxreg_core_item *item);\n+\n+/**\n+ * struct mlxreg_core_grp - attribute group parameters:\n+ *\n+ * @name: attribute group name;\n+ * @type: attribute type;\n+ * @access: attribute access permissions (negative for no access);\n+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;\n+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK, -1 - n/a;\n+ * @cb: device node attribute parsing callback function;\n+ */\n+struct mlxreg_core_grp {\n+\tconst char *name;\n+\tenum mlxreg_core_attr_type type;\n+\tint access;\n+\tint inversed;\n+\tmlxreg_core_parse_np cb;\n+};\n+\n+/**\n+ * struct mlxreg_core_priv_data - driver's private data:\n+ *\n+ * @irq: platform interrupt number;\n+ * @pdev: platform device;\n+ * @led_pdev: led platform device;\n+ * @hp_pdev: hotplug platform device;\n+ * @dev: parent device pointer;\n+ * @regmap: register map of parent device;\n+ * @item: groups control data;\n+ * @led_data: led data;\n+ * @hwmon: hwmon device;\n+ * @mlxreg_core_attr: sysfs attributes array;\n+ * @mlxreg_core_dev_attr: sysfs sensor device attribute array;\n+ * @group: sysfs attribute group;\n+ * @groups: list of sysfs attribute group for hwmon registration;\n+ * @hp_counter: number of the groups with hotplug capability;\n+ * @cell: location of top aggregation interrupt register;\n+ * @mask: top aggregation interrupt common mask;\n+ * @en_dynamic_node: set to true after dynamic device node is enabled;\n+ */\n+struct mlxreg_core_priv_data {\n+\tint irq;\n+\tstruct platform_device *pdev;\n+\tstruct platform_device *led_pdev;\n+\tstruct platform_device *hp_pdev;\n+\tstruct device *dev;\n+\tstruct regmap *regmap;\n+\tstruct mlxreg_core_item *item[MLXREG_CORE_ATTR_GROUP_NUM];\n+\tstruct mlxreg_core_led_platform_data *led_pdata;\n+\tstruct device *hwmon;\n+\tstruct attribute *mlxreg_core_attr[MLXREG_CORE_ATTRS_NUM + 1];\n+\tstruct sensor_device_attribute_2\n+\t\t\tmlxreg_core_dev_attr[MLXREG_CORE_ATTRS_NUM];\n+\tstruct attribute_group group;\n+\tconst struct attribute_group *groups[2];\n+\tu32 hp_counter;\n+\tu32 cell;\n+\tu32 mask;\n+\tbool en_dynamic_node;\n+};\n+\n+/**\n+ * struct mlxreg_core_device_en - Open Firmware property for enabling device\n+ *\n+ * @name - property name;\n+ * @value - property value string;\n+ * @length - length of proprty value string;\n+ *\n+ * The structure is used for the devices, which require some dynamic\n+ * selection operation allowing access to them.\n+ */\n+static struct property mlxreg_core_device_en = {\n+\t.name = MLXREG_CORE_PROP_STATUS,\n+\t.value = MLXREG_CORE_PROP_OKAY,\n+\t.length = sizeof(MLXREG_CORE_PROP_OKAY),\n+};\n+\n+/**\n+ * struct mlxreg_core_device_dis - Open Firmware property for disabling device\n+ *\n+ * @name - property name;\n+ * @value - property value string;\n+ * @length - length of proprty value string;\n+ *\n+ * The structure is used for the devices, which require some dynamic\n+ * selection operation disallowing access to them.\n+ */\n+static struct property mlxreg_core_device_dis = {\n+\t.name = MLXREG_CORE_PROP_STATUS,\n+\t.value = MLXREG_CORE_PROP_DISABLED,\n+\t.length = sizeof(MLXREG_CORE_PROP_DISABLED),\n+};\n+\n+static void mlxreg_core_dev_enable(struct device_node *np)\n+{\n+\t/* Enable and create device. */\n+\tof_update_property(np, &mlxreg_core_device_en);\n+}\n+\n+static void mlxreg_core_dev_disable(struct device_node *np)\n+{\n+\t/* Disable and unregister platform device. */\n+\tof_update_property(np, &mlxreg_core_device_dis);\n+\tof_node_clear_flag(np, OF_POPULATED);\n+}\n+\n+static int mlxreg_core_parser(struct device_node *np, struct device *dev,\n+\t\t\t struct mlxreg_core_item *item)\n+{\n+\tstruct mlxreg_core_data *data = item->data;\n+\tstruct device_node *child, *phandle;\n+\n+\tfor_each_child_of_node(np, child) {\n+\t\tstrlcpy(data->label, child->name, MLXREG_CORE_LABEL_MAX_SIZE);\n+\t\tstrreplace(data->label, '-', ':');\n+\t\tif (of_property_read_u32(child, \"reg\", &data->reg))\n+\t\t\treturn -EINVAL;\n+\n+\t\tof_property_read_u32(child, \"mask\", &data->mask);\n+\t\tof_property_read_u32(child, \"bit\", &data->bit);\n+\n+\t\tphandle = of_parse_phandle(child, \"phandles\", 0);\n+\t\tif (phandle)\n+\t\t\tdata->np = phandle;\n+\n+\t\tdata++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int mlxreg_core_hp_parser(struct device_node *np, struct device *dev,\n+\t\t\t\t struct mlxreg_core_item *item)\n+{\n+\tstruct mlxreg_core_data *data = item->data;\n+\tstruct of_phandle_args args;\n+\tint i;\n+\tint ret;\n+\n+\tif (of_property_read_u32(np, \"aggr\", &item->aggr_mask))\n+\t\treturn -EINVAL;\n+\n+\tif (of_property_read_u32(np, \"reg\", &item->reg))\n+\t\treturn -EINVAL;\n+\n+\tif (of_property_read_u32(np, \"mask\", &item->mask))\n+\t\treturn -EINVAL;\n+\n+\tfor (i = 0; i < item->count; i++) {\n+\t\tret = of_parse_phandle_with_fixed_args(np, \"phandles\", 0,\n+\t\t\t\t\t\t i, &args);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\tdata->np = args.np;\n+\t\tdata++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static int mlxreg_core_asic_parser(struct device_node *np, struct device *dev,\n+\t\t\t\t struct mlxreg_core_item *item)\n+{\n+\tstruct mlxreg_core_data *data = item->data;\n+\tstruct of_phandle_args args;\n+\tu32 regs[16], mask[16];\n+\tint i;\n+\tint ret;\n+\n+\tif (of_property_read_u32(np, \"aggr\", &item->aggr_mask))\n+\t\treturn -EINVAL;\n+\n+\tret = of_property_read_u32_array(np, \"regs\", regs, item->count);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = of_property_read_u32_array(np, \"mask\", mask, item->count);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\titem->health = true;\n+\tfor (i = 0; i < item->count; i++) {\n+\t\tret = of_parse_phandle_with_fixed_args(np, \"phandles\", 0,\n+\t\t\t\t\t\t 0, &args);\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\n+\t\tdata->np = args.np;\n+\t\tdata->reg = regs[i];\n+\t\tdata->mask = mask[i];\n+\t\tdata++;\n+\t}\n+\n+\treturn 0;\n+}\n+\n+static struct mlxreg_core_grp mlxreg_core_grp[] = {\n+\t{ \"psu\", MLXREG_CORE_ATTR_PSU, -1, 1, mlxreg_core_hp_parser },\n+\t{ \"pwr\", MLXREG_CORE_ATTR_PWR, -1, 0, mlxreg_core_hp_parser },\n+\t{ \"fan\", MLXREG_CORE_ATTR_FAN, -1, 1, mlxreg_core_hp_parser },\n+\t{ \"reset\", MLXREG_CORE_ATTR_RST, 2, -1, mlxreg_core_parser },\n+\t{ \"cause\", MLXREG_CORE_ATTR_CAUSE, 1, -1, mlxreg_core_parser },\n+\t{ \"mux\", MLXREG_CORE_ATTR_MUX, 0, -1, mlxreg_core_parser },\n+\t{ \"gprw\", MLXREG_CORE_ATTR_GPRW, 0, -1, mlxreg_core_parser },\n+\t{ \"gpro\", MLXREG_CORE_ATTR_GPRO, 1, -1, mlxreg_core_parser },\n+\t{ \"asic\", MLXREG_CORE_ATTR_ASIC, -1, 0, mlxreg_core_asic_parser },\n+\t{ \"led\", MLXREG_CORE_ATTR_LED, -1, -1, mlxreg_core_parser },\n+\t{ \"host\", MLXREG_CORE_ATTR_HOST, -1, 0, mlxreg_core_hp_parser },\n+};\n+\n+static int\n+mlxreg_core_item_parser(struct device_node *np, struct device *dev,\n+\t\t\tstruct mlxreg_core_item *item,\n+\t\t\tmlxreg_core_parse_np cb)\n+{\n+\titem->count = of_get_child_count(np);\n+\tif (!item->count) {\n+\t\titem->count = of_count_phandle_with_args(np, \"phandles\", NULL);\n+\t\tif (item->count < 0)\n+\t\t\treturn item->count;\n+\t}\n+\n+\titem->data = devm_kzalloc(dev, sizeof(*item->data) * item->count,\n+\t\t\t\t GFP_KERNEL);\n+\tif (!item->data)\n+\t\treturn -ENOMEM;\n+\n+\treturn cb(np, dev, item);\n+}\n+\n+static struct mlxreg_core_data*\n+mlxreg_core_get(struct mlxreg_core_priv_data *priv,\n+\t\tstruct mlxreg_core_grp *grp, int index)\n+{\n+\tint pos;\n+\n+\tif (!index)\n+\t\treturn priv->item[grp->type]->data;\n+\n+\tpos = (index - priv->item[grp->type]->ind) %\n+\t priv->item[grp->type]->count;\n+\n+\treturn priv->item[grp->type]->data + pos;\n+}\n+\n+static ssize_t mlxreg_core_attr_show(struct device *dev,\n+\t\t\t\t struct device_attribute *attr,\n+\t\t\t\t char *buf)\n+{\n+\tstruct mlxreg_core_priv_data *priv = dev_get_drvdata(dev);\n+\tint index = to_sensor_dev_attr_2(attr)->index;\n+\tint nr = to_sensor_dev_attr_2(attr)->nr;\n+\tstruct mlxreg_core_data *data;\n+\tu32 regval = 0;\n+\tint ret;\n+\n+\tswitch (nr) {\n+\tcase MLXREG_CORE_ATTR_CAUSE:\n+\tcase MLXREG_CORE_ATTR_MUX:\n+\t\tdata = mlxreg_core_get(priv, &mlxreg_core_grp[nr], index);\n+\t\tret = regmap_read(priv->regmap, data->reg, ®val);\n+\t\tif (ret)\n+\t\t\tgoto access_error;\n+\n+\t\tregval = !!(data->reg & ~data->mask);\n+\n+\t\tbreak;\n+\n+\tcase MLXREG_CORE_ATTR_GPRW:\n+\tcase MLXREG_CORE_ATTR_GPRO:\n+\t\tdata = mlxreg_core_get(priv, &mlxreg_core_grp[nr], index);\n+\t\tret = regmap_read(priv->regmap, data->reg, ®val);\n+\t\tif (ret)\n+\t\t\tgoto access_error;\n+\n+\t\tbreak;\n+\n+\tcase MLXREG_CORE_ATTR_PSU:\n+\tcase MLXREG_CORE_ATTR_FAN:\n+\tcase MLXREG_CORE_ATTR_PWR:\n+\tcase MLXREG_CORE_ATTR_ASIC:\n+\tcase MLXREG_CORE_ATTR_RST:\n+\tcase MLXREG_CORE_ATTR_LED:\n+\tcase MLXREG_CORE_ATTR_HOST:\n+\t\tbreak;\n+\t}\n+\n+\treturn sprintf(buf, \"%u\\n\", regval);\n+\n+access_error:\n+\treturn ret;\n+}\n+\n+static int\n+mlxreg_core_store(struct mlxreg_core_priv_data *priv,\n+\t\t struct mlxreg_core_data *data, const char *buf, u32 *val)\n+{\n+\tu32 regval;\n+\tint ret;\n+\n+\tret = kstrtou32(buf, MLXREG_CORE_ATTR_VALUE_SIZE, val);\n+\tif (ret)\n+\t\treturn ret;\n+\n+\tret = regmap_read(priv->regmap, data->reg, ®val);\n+\tif (ret)\n+\t\tgoto access_error;\n+\n+\tregval &= data->mask;\n+\n+\t*val = !!(*val);\n+\tif (*val)\n+\t\tregval |= ~data->mask;\n+\telse\n+\t\tregval &= data->mask;\n+\n+\tret = regmap_write(priv->regmap, data->reg, regval);\n+\tif (ret < 0)\n+\t\tgoto access_error;\n+\n+\treturn 0;\n+\n+access_error:\n+\tdev_err(priv->dev, \"Bus access error\\n\");\n+\treturn ret;\n+}\n+\n+static ssize_t mlxreg_core_attr_store(struct device *dev,\n+\t\t\t\t struct device_attribute *attr,\n+\t\t\t\t const char *buf, size_t len)\n+{\n+\tstruct mlxreg_core_priv_data *priv = dev_get_drvdata(dev);\n+\tint index = to_sensor_dev_attr_2(attr)->index;\n+\tint nr = to_sensor_dev_attr_2(attr)->nr;\n+\tstruct mlxreg_core_data *data;\n+\tu32 regval;\n+\tint ret;\n+\n+\tswitch (nr) {\n+\tcase MLXREG_CORE_ATTR_PSU:\n+\tcase MLXREG_CORE_ATTR_PWR:\n+\tcase MLXREG_CORE_ATTR_FAN:\n+\tcase MLXREG_CORE_ATTR_CAUSE:\n+\tcase MLXREG_CORE_ATTR_GPRO:\n+\tcase MLXREG_CORE_ATTR_ASIC:\n+\tcase MLXREG_CORE_ATTR_LED:\n+\tcase MLXREG_CORE_ATTR_HOST:\n+\t\tbreak;\n+\n+\tcase MLXREG_CORE_ATTR_MUX:\n+\t\tdata = mlxreg_core_get(priv, &mlxreg_core_grp[nr], index);\n+\n+\t\tret = mlxreg_core_store(priv, data, buf, ®val);\n+\t\tif (ret)\n+\t\t\tgoto access_error;\n+\n+\t\t/*\n+\t\t * Mux can open and close an access to some devices, which by\n+\t\t * default are un-accessible.\n+\t\t * Create dynamic device, in case it is associated with mux\n+\t\t * attribute. Typical example of such device is SPI flash\n+\t\t * device, which generally is not used by local CPU. For\n+\t\t * example, in case a local CPU is located on Base Management\n+\t\t * Controller board and capable of access to some devices, like\n+\t\t * BIOS or NC-SI flash for some sort of out of service\n+\t\t * maintenance.\n+\t\t * Enabling more than one dynamic device at the mux is not\n+\t\t * allowed.\n+\t\t */\n+\t\tif (regval && data->np && priv->en_dynamic_node)\n+\t\t\tbreak;\n+\n+\t\tif (data->np) {\n+\t\t\tif (regval) {\n+\t\t\t\t/* Enable and create platform device. */\n+\t\t\t\tmlxreg_core_dev_enable(data->np);\n+\t\t\t\tpriv->en_dynamic_node = true;\n+\t\t\t} else {\n+\t\t\t\t/* Disable and unregister platform device. */\n+\t\t\t\tmlxreg_core_dev_disable(data->np);\n+\t\t\t\tpriv->en_dynamic_node = false;\n+\t\t\t}\n+\t\t}\n+\n+\t\tbreak;\n+\n+\tcase MLXREG_CORE_ATTR_RST:\n+\t\tdata = mlxreg_core_get(priv, &mlxreg_core_grp[nr], index);\n+\t\tret = mlxreg_core_store(priv, data, buf, ®val);\n+\t\tif (ret)\n+\t\t\tgoto access_error;\n+\n+\t\tbreak;\n+\n+\tcase MLXREG_CORE_ATTR_GPRW:\n+\t\tret = kstrtou32(buf, MLXREG_CORE_ATTR_VALUE_SIZE, ®val);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\n+\t\tdata = mlxreg_core_get(priv, &mlxreg_core_grp[nr], index);\n+\t\tret = regmap_write(priv->regmap, data->reg, regval);\n+\t\tif (ret)\n+\t\t\tgoto access_error;\n+\n+\t\tbreak;\n+\t}\n+\n+\treturn len;\n+\n+access_error:\n+\tdev_err(priv->dev, \"Failed to store attribute\\n\");\n+\n+\treturn ret;\n+}\n+\n+static int\n+mlxreg_core_add_attr_group(struct mlxreg_core_priv_data *priv,\n+\t\t\t struct mlxreg_core_grp *grp, int id)\n+{\n+\tstruct mlxreg_core_data *data = priv->item[grp->type]->data;\n+\tint i;\n+\n+\t/* Skip group with negative access value. */\n+\tif (grp->access < 0)\n+\t\treturn id;\n+\n+\tpriv->item[grp->type]->ind = id;\n+\tpriv->item[grp->type]->inversed = grp->inversed;\n+\n+\tfor (i = 0; i < priv->item[grp->type]->count; i++, id++, data++) {\n+\t\tpriv->mlxreg_core_attr[id] =\n+\t\t\t\t&priv->mlxreg_core_dev_attr[id].dev_attr.attr;\n+\n+\t\t/* Set attribute name as a label. */\n+\t\tpriv->mlxreg_core_attr[id]->name = devm_kasprintf(priv->dev,\n+\t\t\t\t\t\t\t\t GFP_KERNEL,\n+\t\t\t\t\t\t\t\t data->label);\n+\n+\t\tif (!priv->mlxreg_core_attr[id]->name) {\n+\t\t\tdev_err(priv->dev, \"Memory allocation failed for sysfs attribute %d.\\n\",\n+\t\t\t\tid + 1);\n+\t\t\treturn -ENOMEM;\n+\t\t}\n+\n+\t\tpriv->mlxreg_core_dev_attr[id].nr = grp->type;\n+\n+\t\tswitch (grp->access) {\n+\t\tcase 0:\n+\t\t\tpriv->mlxreg_core_dev_attr[id].dev_attr.attr.mode =\n+\t\t\t\t\t\t\t0644;\n+\t\t\tpriv->mlxreg_core_dev_attr[id].dev_attr.show =\n+\t\t\t\t\t\t\tmlxreg_core_attr_show;\n+\t\t\tpriv->mlxreg_core_dev_attr[id].dev_attr.store =\n+\t\t\t\t\t\t\tmlxreg_core_attr_store;\n+\t\t\tbreak;\n+\n+\t\tcase 1:\n+\t\t\tpriv->mlxreg_core_dev_attr[id].dev_attr.attr.mode =\n+\t\t\t\t\t\t\t0444;\n+\t\t\tpriv->mlxreg_core_dev_attr[id].dev_attr.show =\n+\t\t\t\t\t\t\tmlxreg_core_attr_show;\n+\n+\t\t\tbreak;\n+\n+\t\tcase 2:\n+\t\t\tpriv->mlxreg_core_dev_attr[id].dev_attr.attr.mode =\n+\t\t\t\t\t\t\t0200;\n+\t\t\tpriv->mlxreg_core_dev_attr[id].dev_attr.store =\n+\t\t\t\t\t\t\tmlxreg_core_attr_store;\n+\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\n+\t\t\tbreak;\n+\t\t}\n+\n+\t\tpriv->mlxreg_core_dev_attr[id].dev_attr.attr.name =\n+\t\t\t\t\tpriv->mlxreg_core_attr[id]->name;\n+\t\tpriv->mlxreg_core_dev_attr[id].index = id;\n+\t\tsysfs_attr_init(&priv->mlxreg_core_dev_attr[id].dev_attr.attr);\n+\t}\n+\n+\treturn id;\n+}\n+\n+static int mlxreg_core_attr_init(struct mlxreg_core_priv_data *priv)\n+{\n+\tint i, num_attrs = 0;\n+\tint ret = 0;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(mlxreg_core_grp); i++) {\n+\t\tif (mlxreg_core_grp[i].access >= 0)\n+\t\t\tnum_attrs +=\n+\t\t\t\tpriv->item[mlxreg_core_grp[i].type]->count;\n+\t}\n+\n+\tpriv->group.attrs = devm_kzalloc(&priv->pdev->dev, num_attrs *\n+\t\t\t\t\t sizeof(struct attribute *),\n+\t\t\t\t\t GFP_KERNEL);\n+\tif (!priv->group.attrs)\n+\t\treturn -ENOMEM;\n+\n+\tfor (i = 0; i < ARRAY_SIZE(mlxreg_core_grp); i++) {\n+\t\tret = mlxreg_core_add_attr_group(priv,\n+\t\t\t\t\t\t &mlxreg_core_grp[i],\n+\t\t\t\t\t\t ret);\n+\n+\t\tif (ret < 0)\n+\t\t\treturn ret;\n+\t}\n+\n+\tpriv->group.attrs = priv->mlxreg_core_attr;\n+\tpriv->groups[0] = &priv->group;\n+\tpriv->groups[1] = NULL;\n+\n+\treturn 0;\n+}\n+\n+static int mlxreg_core_set_led(struct mlxreg_core_priv_data *priv)\n+{\n+\tstruct mlxreg_core_led_platform_data *led_pdata;\n+\tint count;\n+\tint err;\n+\n+\tled_pdata = devm_kzalloc(&priv->pdev->dev, sizeof(*led_pdata),\n+\t\t\t\t GFP_KERNEL);\n+\tif (!led_pdata)\n+\t\treturn -ENOMEM;\n+\n+\tcount = priv->item[MLXREG_CORE_ATTR_LED]->count;\n+\tled_pdata->regmap = priv->regmap;\n+\tled_pdata->counter = priv->item[MLXREG_CORE_ATTR_LED]->count;\n+\tled_pdata->data = priv->item[MLXREG_CORE_ATTR_LED]->data;\n+\n+\tpriv->led_pdev = platform_device_alloc(\"leds-mlxreg\", priv->pdev->id);\n+\tif (!priv->led_pdev)\n+\t\treturn -ENOMEM;\n+\n+\tpriv->led_pdev->dev.parent = &priv->pdev->dev;\n+\tpriv->led_pdev->dev.of_node = priv->pdev->dev.of_node;\n+\terr = platform_device_add_data(priv->led_pdev, led_pdata,\n+\t\t\t\t sizeof(*led_pdata));\n+\tif (err) {\n+\t\tplatform_device_put(priv->led_pdev);\n+\n+\t\treturn err;\n+\t}\n+\n+\terr = platform_device_add(priv->led_pdev);\n+\tif (err)\n+\t\tplatform_device_put(priv->led_pdev);\n+\n+\tpriv->led_pdata = led_pdata;\n+\n+\treturn err;\n+}\n+\n+static int mlxreg_core_set_irq(struct mlxreg_core_priv_data *priv)\n+{\n+\tstruct mlxreg_core_item *items[MLXREG_CORE_ATTR_GROUP_NUM], *item;\n+\tstruct mlxreg_core_hotplug_platform_data *hp_pdata;\n+\tenum mlxreg_core_attr_type type;\n+\tstruct mlxreg_core_data *data;\n+\tstruct mlxreg_core_grp *grp;\n+\tint i, j;\n+\tint err;\n+\n+\thp_pdata = devm_kzalloc(&priv->pdev->dev, sizeof(*hp_pdata),\n+\t\t\t\tGFP_KERNEL);\n+\tif (!hp_pdata)\n+\t\treturn -ENOMEM;\n+\n+\t/* Set all the items, capable of interrupt handling. */\n+\tfor (i = 0; i < ARRAY_SIZE(mlxreg_core_grp); i++) {\n+\t\tgrp = &mlxreg_core_grp[i];\n+\t\ttype = grp->type;\n+\t\tif ((grp->inversed >= 0) && (priv->item[type]->count > 0)) {\n+\t\t\titem = priv->item[i];\n+\t\t\titem->inversed = grp->inversed;\n+\t\t\titems[priv->hp_counter] = item;\n+\t\t\tpriv->hp_counter++;\n+\n+\t\t\tdata = item->data;\n+\t\t\tfor (j = 0; j < item->count; j++, data++) {\n+\t\t\t\t/*\n+\t\t\t\t * Set reg and mask for non-health compatible\n+\t\t\t\t * items.\n+\t\t\t\t */\n+\t\t\t\tif (!priv->item[type]->health) {\n+\t\t\t\t\tdata->reg = item->reg;\n+\t\t\t\t\tdata->mask = BIT(j);\n+\t\t\t\t}\n+\n+\t\t\t\t/*\n+\t\t\t\t * Construct an attribute name from the group\n+\t\t\t\t * name and attribute index within the group.\n+\t\t\t\t */\n+\t\t\t\tsprintf(data->label, \"%s%u\", grp->name, j + 1);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\thp_pdata->items = devm_kzalloc(&priv->pdev->dev,\n+\t\t\t\t sizeof(*hp_pdata->items) *\n+\t\t\t\t priv->hp_counter, GFP_KERNEL);\n+\tif (!hp_pdata->items)\n+\t\treturn -ENOMEM;\n+\n+\tfor (i = 0; i < priv->hp_counter; i++)\n+\t\tmemcpy(hp_pdata->items + i, items[i], sizeof(*hp_pdata->items));\n+\n+\thp_pdata->regmap = priv->regmap;\n+\thp_pdata->irq = priv->irq;\n+\thp_pdata->cell = priv->cell;\n+\thp_pdata->mask = priv->mask;\n+\thp_pdata->counter = priv->hp_counter;\n+\n+\tpriv->hp_pdev = platform_device_alloc(\"mlxreg-hotplug\", priv->pdev->id);\n+\tif (!priv->hp_pdev)\n+\t\treturn -ENOMEM;\n+\n+\tpriv->hp_pdev->dev.parent = &priv->pdev->dev;\n+\tpriv->hp_pdev->dev.of_node = priv->pdev->dev.of_node;\n+\terr = platform_device_add_data(priv->hp_pdev, hp_pdata,\n+\t\t\t\t sizeof(*hp_pdata));\n+\tif (err) {\n+\t\tplatform_device_put(priv->hp_pdev);\n+\n+\t\treturn err;\n+\t}\n+\n+\terr = platform_device_add(priv->hp_pdev);\n+\tif (err)\n+\t\tplatform_device_put(priv->hp_pdev);\n+\n+\treturn err;\n+}\n+\n+static int mlxreg_core_probe(struct platform_device *pdev)\n+{\n+\tstruct device_node *child, *np = pdev->dev.of_node;\n+\tstruct mlxreg_core_priv_data *priv;\n+\tstruct mlxreg_core_grp *grp;\n+\tu32 val;\n+\tint i;\n+\tint err;\n+\n+\tpriv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);\n+\tif (!priv)\n+\t\treturn -ENOMEM;\n+\n+\tpriv->regmap = pdev->dev.platform_data;\n+\tpriv->dev = pdev->dev.parent;\n+\tpriv->pdev = pdev;\n+\n+\tfor (i = 0; i < MLXREG_CORE_ATTR_GROUP_NUM; i++) {\n+\t\tpriv->item[i] = devm_kzalloc(&pdev->dev,\n+\t\t\t\t\t sizeof(*priv->item[i]),\n+\t\t\t\t\t GFP_KERNEL);\n+\t\tif (!priv->item[i])\n+\t\t\treturn -ENOMEM;\n+\t}\n+\n+\tif (!of_property_read_u32(np, \"cell\", &val))\n+\t\tpriv->cell = val;\n+\n+\tif (!of_property_read_u32(np, \"mask\", &val))\n+\t\tpriv->mask = val;\n+\n+\t/* Parse device tree table and configure driver's attributes. */\n+\tfor_each_child_of_node(np, child) {\n+\t\tfor (i = 0; i < ARRAY_SIZE(mlxreg_core_grp); i++) {\n+\t\t\tgrp = &mlxreg_core_grp[i];\n+\t\t\tif (!of_node_cmp(child->name, grp->name)) {\n+\t\t\t\terr = mlxreg_core_item_parser(child,\n+\t\t\t\t\t\t\t&priv->pdev->dev,\n+\t\t\t\t\t\t\tpriv->item[grp->type],\n+\t\t\t\t\t\t\tgrp->cb);\n+\t\t\t\tgoto parse_check;\n+\t\t\t}\n+\t\t}\n+parse_check:\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\terr = mlxreg_core_attr_init(priv);\n+\tif (err) {\n+\t\tdev_err(priv->dev, \"Failed to allocate attributes: %d\\n\",\n+\t\t\terr);\n+\t\treturn err;\n+\t}\n+\n+\tpriv->hwmon = devm_hwmon_device_register_with_groups(&pdev->dev,\n+\t\t\t\t\t\"mlxreg_core\", priv, priv->groups);\n+\tif (IS_ERR(priv->hwmon)) {\n+\t\tdev_err(&pdev->dev, \"Failed to register hwmon device %ld\\n\",\n+\t\t\tPTR_ERR(priv->hwmon));\n+\t\treturn PTR_ERR(priv->hwmon);\n+\t}\n+\n+\tif (priv->item[MLXREG_CORE_ATTR_LED] &&\n+\t (priv->item[MLXREG_CORE_ATTR_LED]->count > 0)) {\n+\t\terr = mlxreg_core_set_led(priv);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t}\n+\n+\tpriv->irq = platform_get_irq(pdev, 0);\n+\tif (priv->irq >= 0)\n+\t\terr = mlxreg_core_set_irq(priv);\n+\n+\tdev_set_drvdata(&pdev->dev, priv);\n+\n+\treturn 0;\n+}\n+\n+static int mlxreg_core_remove(struct platform_device *pdev)\n+{\n+\tstruct mlxreg_core_priv_data *priv = dev_get_drvdata(&pdev->dev);\n+\n+\tif (priv->hp_pdev)\n+\t\tplatform_device_unregister(priv->hp_pdev);\n+\n+\tif (priv->led_pdev)\n+\t\tplatform_device_unregister(priv->led_pdev);\n+\n+\treturn 0;\n+}\n+\n+static const struct of_device_id mlxreg_core_dt_match[] = {\n+\t{ .compatible = \"mellanox,mlxreg-core\" },\n+\t{ },\n+};\n+MODULE_DEVICE_TABLE(of, mlxreg_core_dt_match);\n+\n+static struct platform_driver mlxreg_core_driver = {\n+\t.driver = {\n+\t .name = \"mlxreg-core\",\n+\t .of_match_table = of_match_ptr(mlxreg_core_dt_match),\n+\t},\n+\t.probe = mlxreg_core_probe,\n+\t.remove = mlxreg_core_remove,\n+};\n+\n+module_platform_driver(mlxreg_core_driver);\n+\n+MODULE_AUTHOR(\"Vadim Pasternak <vadimp@mellanox.com>\");\n+MODULE_DESCRIPTION(\"Mellanox regmap core driver\");\n+MODULE_LICENSE(\"Dual BSD/GPL\");\n+MODULE_ALIAS(\"platform:mlxreg-core\");\ndiff --git a/include/linux/platform_data/mlxreg.h b/include/linux/platform_data/mlxreg.h\nnew file mode 100644\nindex 0000000..456b805\n--- /dev/null\n+++ b/include/linux/platform_data/mlxreg.h\n@@ -0,0 +1,138 @@\n+/*\n+ * Copyright (c) 2017 Mellanox Technologies. All rights reserved.\n+ * Copyright (c) 2017 Vadim Pasternak <vadimp@mellanox.com>\n+ *\n+ * Redistribution and use in source and binary forms, with or without\n+ * modification, are permitted provided that the following conditions are met:\n+ *\n+ * 1. Redistributions of source code must retain the above copyright\n+ * notice, this list of conditions and the following disclaimer.\n+ * 2. Redistributions in binary form must reproduce the above copyright\n+ * notice, this list of conditions and the following disclaimer in the\n+ * documentation and/or other materials provided with the distribution.\n+ * 3. Neither the names of the copyright holders nor the names of its\n+ * contributors may be used to endorse or promote products derived from\n+ * this software without specific prior written permission.\n+ *\n+ * Alternatively, this software may be distributed under the terms of the\n+ * GNU General Public License (\"GPL\") version 2 as published by the Free\n+ * Software Foundation.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\n+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE\n+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\n+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\n+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\n+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\n+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\n+ * POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+#ifndef __LINUX_PLATFORM_DATA_MLXREG_H\n+#define __LINUX_PLATFORM_DATA_MLXREG_H\n+\n+#define MLXREG_CORE_LABEL_MAX_SIZE\t32\n+\n+/**\n+ * struct mlxreg_hotplug_device - I2C device data:\n+ *\n+ * @adapter: I2C device adapter;\n+ * @client: I2C device client;\n+ * @brdinfo: device board information;\n+ * @nr: I2C device adapter number, to which device is to be attached;\n+ *\n+ * Structure represents I2C hotplug device static data (board topology) and\n+ * dynamic data (related kernel objects handles).\n+ */\n+struct mlxreg_hotplug_device {\n+\tstruct i2c_adapter *adapter;\n+\tstruct i2c_client *client;\n+\tstruct i2c_board_info *brdinfo;\n+\tint nr;\n+};\n+\n+/**\n+ * struct mlxreg_core_data - attributes control data:\n+ *\n+ * @label: attribute label;\n+ * @label: attribute register offset;\n+ * @reg: attribute register;\n+ * @mask: attribute access mask;\n+ * @bit: attribute effective bit;\n+ * @np - pointer to node platform associated with attribute;\n+ * @hpdev - hotplug device data;\n+ * @health_cntr: dynamic device health indication counter;\n+ * @attached: true if device has been attached after good helath indication;\n+ */\n+struct mlxreg_core_data {\n+\tchar label[MLXREG_CORE_LABEL_MAX_SIZE];\n+\tu32 reg;\n+\tu32 mask;\n+\tu32 bit;\n+\tstruct device_node *np;\n+\tstruct mlxreg_hotplug_device hpdev;\n+\tu8 health_cntr;\n+\tbool attached;\n+};\n+\n+/**\n+ * struct mlxreg_core_item - same type components controlled by the driver:\n+ *\n+ * @data: component data;\n+ * @aggr_mask: group aggregation mask;\n+ * @reg: group interrupt status register;\n+ * @mask: group interrupt mask;\n+ * @cache: last status value for elements fro the same group;\n+ * @count: number of available elements in the group;\n+ * @ind: element's index inside the group;\n+ * @inversed: if 0: 0 for signal status is OK, if 1 - 1 is OK;\n+ * @health: true if device has health indication, false in other case;\n+ */\n+struct mlxreg_core_item {\n+\tstruct mlxreg_core_data *data;\n+\tu32 aggr_mask;\n+\tu32 reg;\n+\tu32 mask;\n+\tu32 cache;\n+\tu8 count;\n+\tu8 ind;\n+\tu8 inversed;\n+\tu8 health;\n+};\n+\n+/**\n+ * struct mlxreg_core_led_platform_data - led platform data:\n+ *\n+ * @led_data: led private data;\n+ * @regmap: register map of parent device;\n+ * @counter: number of led instances;\n+ */\n+struct mlxreg_core_led_platform_data {\n+\tstruct mlxreg_core_data *data;\n+\tvoid *regmap;\n+\tint counter;\n+};\n+\n+/**\n+ * struct mlxreg_core_hotplug_platform_data - hotplug platform data:\n+ *\n+ * @items: same type components with the hotplug capability;\n+ * @irq: platform interrupt number;\n+ * @regmap: register map of parent device;\n+ * @counter: number of the components with the hotplug capability;\n+ * @cell: location of top aggregation interrupt register;\n+ * @mask: top aggregation interrupt common mask;\n+ */\n+struct mlxreg_core_hotplug_platform_data {\n+\tstruct mlxreg_core_item *items;\n+\tint irq;\n+\tvoid *regmap;\n+\tint counter;\n+\tu32 cell;\n+\tu32 mask;\n+};\n+\n+#endif /* __LINUX_PLATFORM_DATA_MLXREG_H */\n", "prefixes": [ "v4", "1/2" ] }