|
@@ -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, ®);
|
|
|
+ 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);
|
|
|
|