ipmi: bt-bmc: Use a regmap for register access
authorAndrew Jeffery <andrew@aj.id.au>
Mon, 20 Feb 2017 15:23:00 +0000 (01:53 +1030)
committerCorey Minyard <cminyard@mvista.com>
Mon, 20 Feb 2017 17:00:48 +0000 (11:00 -0600)
The registers for the bt-bmc device live under the Aspeed LPC
controller. Devicetree bindings have recently been introduced for the
LPC controller where the "host" portion of the LPC register space is
described as a syscon device. Future devicetrees describing the bt-bmc
device should nest its node under the appropriate "simple-mfd", "syscon"
compatible node.

This change allows the bt-bmc driver to function with both syscon and
non-syscon- based devicetree descriptions by always using a regmap for
register access, either retrieved from the parent syscon device or
instantiated if none exists.

Signed-off-by: Andrew Jeffery <andrew@aj.id.au>
Reviewed-by: Cédric Le Goater <clg@kaod.org>
Signed-off-by: Corey Minyard <cminyard@mvista.com>
drivers/char/ipmi/Kconfig
drivers/char/ipmi/bt-bmc.c

index 7f81665..90f3edf 100644 (file)
@@ -78,7 +78,8 @@ config IPMI_POWEROFF
 endif # IPMI_HANDLER
 
 config ASPEED_BT_IPMI_BMC
-       depends on ARCH_ASPEED
+       depends on ARCH_ASPEED || COMPILE_TEST
+       depends on REGMAP && REGMAP_MMIO && MFD_SYSCON
        tristate "BT IPMI bmc driver"
        help
          Provides a driver for the BT (Block Transfer) IPMI interface
index fc9e889..d6f5d9e 100644 (file)
 #include <linux/errno.h>
 #include <linux/interrupt.h>
 #include <linux/io.h>
+#include <linux/mfd/syscon.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
+#include <linux/of.h>
 #include <linux/platform_device.h>
 #include <linux/poll.h>
+#include <linux/regmap.h>
 #include <linux/sched.h>
 #include <linux/timer.h>
 
@@ -60,7 +63,8 @@
 struct bt_bmc {
        struct device           dev;
        struct miscdevice       miscdev;
-       void __iomem            *base;
+       struct regmap           *map;
+       int                     offset;
        int                     irq;
        wait_queue_head_t       queue;
        struct timer_list       poll_timer;
@@ -69,14 +73,29 @@ struct bt_bmc {
 
 static atomic_t open_count = ATOMIC_INIT(0);
 
+static const struct regmap_config bt_regmap_cfg = {
+       .reg_bits = 32,
+       .val_bits = 32,
+       .reg_stride = 4,
+};
+
 static u8 bt_inb(struct bt_bmc *bt_bmc, int reg)
 {
-       return ioread8(bt_bmc->base + reg);
+       uint32_t val = 0;
+       int rc;
+
+       rc = regmap_read(bt_bmc->map, bt_bmc->offset + reg, &val);
+       WARN(rc != 0, "regmap_read() failed: %d\n", rc);
+
+       return rc == 0 ? (u8) val : 0;
 }
 
 static void bt_outb(struct bt_bmc *bt_bmc, u8 data, int reg)
 {
-       iowrite8(data, bt_bmc->base + reg);
+       int rc;
+
+       rc = regmap_write(bt_bmc->map, bt_bmc->offset + reg, data);
+       WARN(rc != 0, "regmap_write() failed: %d\n", rc);
 }
 
 static void clr_rd_ptr(struct bt_bmc *bt_bmc)
@@ -367,14 +386,18 @@ static irqreturn_t bt_bmc_irq(int irq, void *arg)
 {
        struct bt_bmc *bt_bmc = arg;
        u32 reg;
+       int rc;
+
+       rc = regmap_read(bt_bmc->map, bt_bmc->offset + BT_CR2, &reg);
+       if (rc)
+               return IRQ_NONE;
 
-       reg = ioread32(bt_bmc->base + BT_CR2);
        reg &= BT_CR2_IRQ_H2B | BT_CR2_IRQ_HBUSY;
        if (!reg)
                return IRQ_NONE;
 
        /* ack pending IRQs */
-       iowrite32(reg, bt_bmc->base + BT_CR2);
+       regmap_write(bt_bmc->map, bt_bmc->offset + BT_CR2, reg);
 
        wake_up(&bt_bmc->queue);
        return IRQ_HANDLED;
@@ -384,7 +407,6 @@ static int bt_bmc_config_irq(struct bt_bmc *bt_bmc,
                             struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       u32 reg;
        int rc;
 
        bt_bmc->irq = platform_get_irq(pdev, 0);
@@ -405,18 +427,17 @@ static int bt_bmc_config_irq(struct bt_bmc *bt_bmc,
         * will be cleared (along with B2H) when we can write the next
         * message to the BT buffer
         */
-       reg = ioread32(bt_bmc->base + BT_CR1);
-       reg |= BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY;
-       iowrite32(reg, bt_bmc->base + BT_CR1);
+       rc = regmap_update_bits(bt_bmc->map, bt_bmc->offset + BT_CR1,
+                               (BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY),
+                               (BT_CR1_IRQ_H2B | BT_CR1_IRQ_HBUSY));
 
-       return 0;
+       return rc;
 }
 
 static int bt_bmc_probe(struct platform_device *pdev)
 {
        struct bt_bmc *bt_bmc;
        struct device *dev;
-       struct resource *res;
        int rc;
 
        if (!pdev || !pdev->dev.of_node)
@@ -431,10 +452,27 @@ static int bt_bmc_probe(struct platform_device *pdev)
 
        dev_set_drvdata(&pdev->dev, bt_bmc);
 
-       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
-       bt_bmc->base = devm_ioremap_resource(&pdev->dev, res);
-       if (IS_ERR(bt_bmc->base))
-               return PTR_ERR(bt_bmc->base);
+       bt_bmc->map = syscon_node_to_regmap(pdev->dev.parent->of_node);
+       if (IS_ERR(bt_bmc->map)) {
+               struct resource *res;
+               void __iomem *base;
+
+               /*
+                * Assume it's not the MFD-based devicetree description, in
+                * which case generate a regmap ourselves
+                */
+               res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+               base = devm_ioremap_resource(&pdev->dev, res);
+               if (IS_ERR(base))
+                       return PTR_ERR(base);
+
+               bt_bmc->map = devm_regmap_init_mmio(dev, base, &bt_regmap_cfg);
+               bt_bmc->offset = 0;
+       } else {
+               rc = of_property_read_u32(dev->of_node, "reg", &bt_bmc->offset);
+               if (rc)
+                       return rc;
+       }
 
        mutex_init(&bt_bmc->mutex);
        init_waitqueue_head(&bt_bmc->queue);
@@ -461,12 +499,12 @@ static int bt_bmc_probe(struct platform_device *pdev)
                add_timer(&bt_bmc->poll_timer);
        }
 
-       iowrite32((BT_IO_BASE << BT_CR0_IO_BASE) |
-                 (BT_IRQ << BT_CR0_IRQ) |
-                 BT_CR0_EN_CLR_SLV_RDP |
-                 BT_CR0_EN_CLR_SLV_WRP |
-                 BT_CR0_ENABLE_IBT,
-                 bt_bmc->base + BT_CR0);
+       regmap_write(bt_bmc->map, bt_bmc->offset + BT_CR0,
+                    (BT_IO_BASE << BT_CR0_IO_BASE) |
+                    (BT_IRQ << BT_CR0_IRQ) |
+                    BT_CR0_EN_CLR_SLV_RDP |
+                    BT_CR0_EN_CLR_SLV_WRP |
+                    BT_CR0_ENABLE_IBT);
 
        clr_b_busy(bt_bmc);