[PATCH] regmap: add virtual PMIC IPC bus support

From: qipeng.zha
Date: Mon Apr 20 2015 - 11:36:18 EST


From: "qipeng.zha" <qipeng.zha@xxxxxxxxx>

There defined Whiskey Cove PMIC controller on one Intel platform,
and all registers on this PMIC are accessed by IPC commands.
This patch is to utilize regmap framework to access PMIC registers
for PMIC core and device drivers.

Signed-off-by: qipeng.zha <qipeng.zha@xxxxxxxxx>
---
drivers/base/regmap/Kconfig | 5 +-
drivers/base/regmap/Makefile | 1 +
drivers/base/regmap/regmap-pmic-ipc.c | 128 ++++++++++++++++++++++++++++++++++
include/linux/mfd/intel_soc_pmic.h | 2 +
include/linux/regmap.h | 5 ++
5 files changed, 140 insertions(+), 1 deletion(-)
create mode 100644 drivers/base/regmap/regmap-pmic-ipc.c

diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index db9d00c3..c6ab5a9 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -3,7 +3,7 @@
# subsystems should select the appropriate symbols.

config REGMAP
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
+ default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ || REGMAP_PMIC_IPC)
select LZO_COMPRESS
select LZO_DECOMPRESS
select IRQ_DOMAIN if REGMAP_IRQ
@@ -29,3 +29,6 @@ config REGMAP_MMIO

config REGMAP_IRQ
bool
+
+config REGMAP_PMIC_IPC
+ bool
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index 609e4c8..fb859c0 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
obj-$(CONFIG_REGMAP_MMIO) += regmap-mmio.o
obj-$(CONFIG_REGMAP_IRQ) += regmap-irq.o
+obj-$(CONFIG_REGMAP_IRQ) += regmap-pmic-ipc.o
diff --git a/drivers/base/regmap/regmap-pmic-ipc.c b/drivers/base/regmap/regmap-pmic-ipc.c
new file mode 100644
index 0000000..2895d22
--- /dev/null
+++ b/drivers/base/regmap/regmap-pmic-ipc.c
@@ -0,0 +1,128 @@
+/*
+ * Register map access API - Intel PMIC IPC support
+ *
+ * (C) Copyright 2015 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2
+ * of the License.
+ *
+ */
+
+#include <linux/regmap.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <asm/intel_pmc_ipc.h>
+#include "internal.h"
+
+#define REG_ADDR_MASK 0xFF00
+#define REG_ADDR_SHIFT 8
+#define REG_OFFSET_MASK 0xFF
+
+static int regmap_ipc_byte_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ int ret;
+ int i2c_addr;
+ u8 ipc_in[2];
+ u8 ipc_out[4];
+ struct intel_soc_pmic *pmic = context;
+
+ if (reg & REG_ADDR_MASK)
+ i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
+ else {
+ i2c_addr = pmic->default_i2c_addr;
+ if (!i2c_addr) {
+ dev_err(pmic->dev, "Wrong register addr to read\n");
+ return -EINVAL;
+ }
+ }
+ reg &= REG_OFFSET_MASK;
+
+ ipc_in[0] = reg;
+ ipc_in[1] = i2c_addr;
+ ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS,
+ PMC_IPC_PMIC_ACCESS_READ,
+ ipc_in, sizeof(ipc_in), (u32 *)ipc_out, 1);
+ if (ret) {
+ dev_err(pmic->dev, "Err: ipc read pmic\n");
+ return ret;
+ }
+ *val = ipc_out[0];
+ return 0;
+}
+
+static int regmap_ipc_byte_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ int ret;
+ int i2c_addr;
+ u8 ipc_in[3];
+ struct intel_soc_pmic *pmic = context;
+
+ if (reg & REG_ADDR_MASK)
+ i2c_addr = (reg & REG_ADDR_MASK) >> REG_ADDR_SHIFT;
+ else {
+ i2c_addr = pmic->default_i2c_addr;
+ if (!i2c_addr) {
+ dev_err(pmic->dev, "Wrong register addr to write\n");
+ return -EINVAL;
+ }
+ }
+ reg &= REG_OFFSET_MASK;
+
+ ipc_in[0] = reg;
+ ipc_in[1] = i2c_addr;
+ ipc_in[2] = val;
+ ret = intel_pmc_ipc_command(PMC_IPC_PMIC_ACCESS,
+ PMC_IPC_PMIC_ACCESS_WRITE,
+ ipc_in, sizeof(ipc_in), NULL, 0);
+ if (ret) {
+ dev_err(pmic->dev, "Err: ipc write pmic\n");
+ return ret;
+ }
+ return 0;
+}
+
+static struct regmap_bus ipc_regmap_bus = {
+ .reg_write = regmap_ipc_byte_reg_write,
+ .reg_read = regmap_ipc_byte_reg_read,
+};
+
+/**
+ * regmap_init_pmic_ipc(): Initialise register map
+ *
+ * @pmic: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+struct regmap *regmap_init_pmic_ipc(struct intel_soc_pmic *pmic,
+ const struct regmap_config *config)
+{
+ return regmap_init(pmic->dev, &ipc_regmap_bus, pmic, config);
+}
+EXPORT_SYMBOL_GPL(regmap_init_pmic_ipc);
+
+/**
+ * devm_regmap_init_pmic_ipc(): Initialise managed register map
+ *
+ * @pmic: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap. The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_pmic_ipc(struct intel_soc_pmic *pmic,
+ const struct regmap_config *config)
+{
+ return devm_regmap_init(pmic->dev, &ipc_regmap_bus, pmic, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_pmic_ipc);
+
+MODULE_AUTHOR("qipeng.zha@xxxxxxxxx");
+MODULE_LICENSE("GPL");
diff --git a/include/linux/mfd/intel_soc_pmic.h b/include/linux/mfd/intel_soc_pmic.h
index abcbfcf..74ee3d2 100644
--- a/include/linux/mfd/intel_soc_pmic.h
+++ b/include/linux/mfd/intel_soc_pmic.h
@@ -25,6 +25,8 @@ struct intel_soc_pmic {
int irq;
struct regmap *regmap;
struct regmap_irq_chip_data *irq_chip_data;
+ struct device *dev;
+ int default_i2c_addr;
};

#endif /* __INTEL_SOC_PMIC_H__ */
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index 116655d..11bbf1d 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -28,6 +28,7 @@ struct regmap;
struct regmap_range_cfg;
struct regmap_field;
struct snd_ac97;
+struct intel_soc_pmic;

/* An enum of all the supported cache types */
enum regcache_type {
@@ -343,6 +344,8 @@ struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
const struct regmap_config *config);
struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config);
+struct regmap *regmap_init_pmic_ipc(struct intel_soc_pmic *pmic,
+ const struct regmap_config *config);

struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
@@ -361,6 +364,8 @@ struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
const struct regmap_config *config);
struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
const struct regmap_config *config);
+struct regmap *devm_regmap_init_pmic_ipc(struct intel_soc_pmic *pmic,
+ const struct regmap_config *config);

bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);

--
1.8.3.2

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/