Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754273AbbDTPgP (ORCPT ); Mon, 20 Apr 2015 11:36:15 -0400 Received: from mga01.intel.com ([192.55.52.88]:32577 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753006AbbDTPgN (ORCPT ); Mon, 20 Apr 2015 11:36:13 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.11,609,1422950400"; d="scan'208";a="716347688" From: "qipeng.zha" To: linux-kernel@vger.kernel.org Cc: broonie@kernel.org, fei.yang@intel.com, huiquan.zhong@intel.com, jason.cj.chen@intel.com, qi.zheng@intel.com, qipeng.zha@intel.com Subject: [PATCH] regmap: add virtual PMIC IPC bus support Date: Tue, 21 Apr 2015 07:38:58 +0800 Message-Id: <1429573138-68002-1-git-send-email-qipeng.zha@intel.com> X-Mailer: git-send-email 1.8.3.2 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7230 Lines: 231 From: "qipeng.zha" 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 --- 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 +#include +#include +#include +#include +#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@intel.com"); +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@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/