Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: hi655x: Add MFD driver for hi655x

Add PMIC MFD driver to support hisilicon hi665x.

Signed-off-by: Chen Feng <puck.chen@hisilicon.com>
Signed-off-by: Fei Wang <w.f@huawei.com>
Signed-off-by: Xinwei Kong <kong.kongxinwei@hisilicon.com>
Reviewed-by: Haojian Zhuang <haojian.zhuang@linaro.org>
Signed-off-by: Lee Jones <lee.jones@linaro.org>

authored by

Chen Feng and committed by
Lee Jones
b52207ef 68b21094

+228
+10
drivers/mfd/Kconfig
··· 319 319 menus in order to enable them. 320 320 We communicate with the Hi6421 via memory-mapped I/O. 321 321 322 + config MFD_HI655X_PMIC 323 + tristate "HiSilicon Hi655X series PMU/Codec IC" 324 + depends on ARCH_HISI || COMPILE_TEST 325 + depends on OF 326 + select MFD_CORE 327 + select REGMAP_MMIO 328 + select REGMAP_IRQ 329 + help 330 + Select this option to enable Hisilicon hi655x series pmic driver. 331 + 322 332 config HTC_EGPIO 323 333 bool "HTC EGPIO support" 324 334 depends on GPIOLIB && ARM
+1
drivers/mfd/Makefile
··· 196 196 obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o 197 197 obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o 198 198 obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o 199 + obj-$(CONFIG_MFD_HI655X_PMIC) += hi655x-pmic.o 199 200 obj-$(CONFIG_MFD_DLN2) += dln2.o 200 201 obj-$(CONFIG_MFD_RT5033) += rt5033.o 201 202 obj-$(CONFIG_MFD_SKY81452) += sky81452.o
+162
drivers/mfd/hi655x-pmic.c
··· 1 + /* 2 + * Device driver for MFD hi655x PMIC 3 + * 4 + * Copyright (c) 2016 Hisilicon. 5 + * 6 + * Authors: 7 + * Chen Feng <puck.chen@hisilicon.com> 8 + * Fei Wang <w.f@huawei.com> 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License version 2 as 12 + * published by the Free Software Foundation. 13 + */ 14 + 15 + #include <linux/gpio.h> 16 + #include <linux/io.h> 17 + #include <linux/interrupt.h> 18 + #include <linux/init.h> 19 + #include <linux/mfd/core.h> 20 + #include <linux/mfd/hi655x-pmic.h> 21 + #include <linux/module.h> 22 + #include <linux/of_gpio.h> 23 + #include <linux/of_platform.h> 24 + #include <linux/platform_device.h> 25 + #include <linux/regmap.h> 26 + 27 + static const struct mfd_cell hi655x_pmic_devs[] = { 28 + { .name = "hi655x-regulator", }, 29 + }; 30 + 31 + static const struct regmap_irq hi655x_irqs[] = { 32 + { .reg_offset = 0, .mask = OTMP_D1R_INT }, 33 + { .reg_offset = 0, .mask = VSYS_2P5_R_INT }, 34 + { .reg_offset = 0, .mask = VSYS_UV_D3R_INT }, 35 + { .reg_offset = 0, .mask = VSYS_6P0_D200UR_INT }, 36 + { .reg_offset = 0, .mask = PWRON_D4SR_INT }, 37 + { .reg_offset = 0, .mask = PWRON_D20F_INT }, 38 + { .reg_offset = 0, .mask = PWRON_D20R_INT }, 39 + { .reg_offset = 0, .mask = RESERVE_INT }, 40 + }; 41 + 42 + static const struct regmap_irq_chip hi655x_irq_chip = { 43 + .name = "hi655x-pmic", 44 + .irqs = hi655x_irqs, 45 + .num_regs = 1, 46 + .num_irqs = ARRAY_SIZE(hi655x_irqs), 47 + .status_base = HI655X_IRQ_STAT_BASE, 48 + .mask_base = HI655X_IRQ_MASK_BASE, 49 + }; 50 + 51 + static struct regmap_config hi655x_regmap_config = { 52 + .reg_bits = 32, 53 + .reg_stride = HI655X_STRIDE, 54 + .val_bits = 8, 55 + .max_register = HI655X_BUS_ADDR(0xFFF), 56 + }; 57 + 58 + static void hi655x_local_irq_clear(struct regmap *map) 59 + { 60 + int i; 61 + 62 + regmap_write(map, HI655X_ANA_IRQM_BASE, HI655X_IRQ_CLR); 63 + for (i = 0; i < HI655X_IRQ_ARRAY; i++) { 64 + regmap_write(map, HI655X_IRQ_STAT_BASE + i * HI655X_STRIDE, 65 + HI655X_IRQ_CLR); 66 + } 67 + } 68 + 69 + static int hi655x_pmic_probe(struct platform_device *pdev) 70 + { 71 + int ret; 72 + struct hi655x_pmic *pmic; 73 + struct device *dev = &pdev->dev; 74 + struct device_node *np = dev->of_node; 75 + void __iomem *base; 76 + 77 + pmic = devm_kzalloc(dev, sizeof(*pmic), GFP_KERNEL); 78 + if (!pmic) 79 + return -ENOMEM; 80 + pmic->dev = dev; 81 + 82 + pmic->res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 83 + if (!pmic->res) 84 + return -ENOENT; 85 + 86 + base = devm_ioremap_resource(dev, pmic->res); 87 + if (!base) 88 + return -ENOMEM; 89 + 90 + pmic->regmap = devm_regmap_init_mmio_clk(dev, NULL, base, 91 + &hi655x_regmap_config); 92 + 93 + regmap_read(pmic->regmap, HI655X_BUS_ADDR(HI655X_VER_REG), &pmic->ver); 94 + if ((pmic->ver < PMU_VER_START) || (pmic->ver > PMU_VER_END)) { 95 + dev_warn(dev, "PMU version %d unsupported\n", pmic->ver); 96 + return -EINVAL; 97 + } 98 + 99 + hi655x_local_irq_clear(pmic->regmap); 100 + 101 + pmic->gpio = of_get_named_gpio(np, "pmic-gpios", 0); 102 + if (!gpio_is_valid(pmic->gpio)) { 103 + dev_err(dev, "Failed to get the pmic-gpios\n"); 104 + return -ENODEV; 105 + } 106 + 107 + ret = devm_gpio_request_one(dev, pmic->gpio, GPIOF_IN, 108 + "hi655x_pmic_irq"); 109 + if (ret < 0) { 110 + dev_err(dev, "Failed to request gpio %d ret = %d\n", 111 + pmic->gpio, ret); 112 + return ret; 113 + } 114 + 115 + ret = regmap_add_irq_chip(pmic->regmap, gpio_to_irq(pmic->gpio), 116 + IRQF_TRIGGER_LOW | IRQF_NO_SUSPEND, 0, 117 + &hi655x_irq_chip, &pmic->irq_data); 118 + if (ret) { 119 + dev_err(dev, "Failed to obtain 'hi655x_pmic_irq' %d\n", ret); 120 + return ret; 121 + } 122 + 123 + platform_set_drvdata(pdev, pmic); 124 + 125 + ret = mfd_add_devices(dev, PLATFORM_DEVID_AUTO, hi655x_pmic_devs, 126 + ARRAY_SIZE(hi655x_pmic_devs), NULL, 0, NULL); 127 + if (ret) { 128 + dev_err(dev, "Failed to register device %d\n", ret); 129 + regmap_del_irq_chip(gpio_to_irq(pmic->gpio), pmic->irq_data); 130 + return ret; 131 + } 132 + 133 + return 0; 134 + } 135 + 136 + static int hi655x_pmic_remove(struct platform_device *pdev) 137 + { 138 + struct hi655x_pmic *pmic = platform_get_drvdata(pdev); 139 + 140 + regmap_del_irq_chip(gpio_to_irq(pmic->gpio), pmic->irq_data); 141 + mfd_remove_devices(&pdev->dev); 142 + return 0; 143 + } 144 + 145 + static const struct of_device_id hi655x_pmic_match[] = { 146 + { .compatible = "hisilicon,hi655x-pmic", }, 147 + {}, 148 + }; 149 + 150 + static struct platform_driver hi655x_pmic_driver = { 151 + .driver = { 152 + .name = "hi655x-pmic", 153 + .of_match_table = of_match_ptr(hi655x_pmic_match), 154 + }, 155 + .probe = hi655x_pmic_probe, 156 + .remove = hi655x_pmic_remove, 157 + }; 158 + module_platform_driver(hi655x_pmic_driver); 159 + 160 + MODULE_AUTHOR("Chen Feng <puck.chen@hisilicon.com>"); 161 + MODULE_DESCRIPTION("Hisilicon hi655x PMIC driver"); 162 + MODULE_LICENSE("GPL v2");
+55
include/linux/mfd/hi655x-pmic.h
··· 1 + /* 2 + * Device driver for regulators in hi655x IC 3 + * 4 + * Copyright (c) 2016 Hisilicon. 5 + * 6 + * Authors: 7 + * Chen Feng <puck.chen@hisilicon.com> 8 + * Fei Wang <w.f@huawei.com> 9 + * 10 + * This program is free software; you can redistribute it and/or modify 11 + * it under the terms of the GNU General Public License version 2 as 12 + * published by the Free Software Foundation. 13 + */ 14 + 15 + #ifndef __HI655X_PMIC_H 16 + #define __HI655X_PMIC_H 17 + 18 + /* Hi655x registers are mapped to memory bus in 4 bytes stride */ 19 + #define HI655X_STRIDE 4 20 + #define HI655X_BUS_ADDR(x) ((x) << 2) 21 + 22 + #define HI655X_BITS 8 23 + 24 + #define HI655X_NR_IRQ 32 25 + 26 + #define HI655X_IRQ_STAT_BASE (0x003 << 2) 27 + #define HI655X_IRQ_MASK_BASE (0x007 << 2) 28 + #define HI655X_ANA_IRQM_BASE (0x1b5 << 2) 29 + #define HI655X_IRQ_ARRAY 4 30 + #define HI655X_IRQ_MASK 0xFF 31 + #define HI655X_IRQ_CLR 0xFF 32 + #define HI655X_VER_REG 0x00 33 + 34 + #define PMU_VER_START 0x10 35 + #define PMU_VER_END 0x38 36 + 37 + #define RESERVE_INT BIT(7) 38 + #define PWRON_D20R_INT BIT(6) 39 + #define PWRON_D20F_INT BIT(5) 40 + #define PWRON_D4SR_INT BIT(4) 41 + #define VSYS_6P0_D200UR_INT BIT(3) 42 + #define VSYS_UV_D3R_INT BIT(2) 43 + #define VSYS_2P5_R_INT BIT(1) 44 + #define OTMP_D1R_INT BIT(0) 45 + 46 + struct hi655x_pmic { 47 + struct resource *res; 48 + struct device *dev; 49 + struct regmap *regmap; 50 + int gpio; 51 + unsigned int ver; 52 + struct regmap_irq_chip_data *irq_data; 53 + }; 54 + 55 + #endif