Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb994594 authored by Andrew Jeffery's avatar Andrew Jeffery Committed by Corey Minyard
Browse files

ipmi: bt-bmc: Use a regmap for register access



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: default avatarAndrew Jeffery <andrew@aj.id.au>
Reviewed-by: default avatarCédric Le Goater <clg@kaod.org>
Signed-off-by: default avatarCorey Minyard <cminyard@mvista.com>
parent db3b7e13
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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
+59 −21
Original line number Diff line number Diff line
@@ -12,10 +12,13 @@
#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);

	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);
	bt_bmc->base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(bt_bmc->base))
		return PTR_ERR(bt_bmc->base);
		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) |
	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,
		  bt_bmc->base + BT_CR0);
		     BT_CR0_ENABLE_IBT);

	clr_b_busy(bt_bmc);