linux/drivers/mfd/vexpress-sysreg.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 *
   4 * Copyright (C) 2012 ARM Limited
   5 */
   6
   7#include <linux/gpio/driver.h>
   8#include <linux/err.h>
   9#include <linux/io.h>
  10#include <linux/mfd/core.h>
  11#include <linux/of_address.h>
  12#include <linux/of_platform.h>
  13#include <linux/platform_data/syscon.h>
  14#include <linux/platform_device.h>
  15#include <linux/slab.h>
  16#include <linux/stat.h>
  17#include <linux/vexpress.h>
  18
  19#define SYS_ID                  0x000
  20#define SYS_SW                  0x004
  21#define SYS_LED                 0x008
  22#define SYS_100HZ               0x024
  23#define SYS_FLAGSSET            0x030
  24#define SYS_FLAGSCLR            0x034
  25#define SYS_NVFLAGS             0x038
  26#define SYS_NVFLAGSSET          0x038
  27#define SYS_NVFLAGSCLR          0x03c
  28#define SYS_MCI                 0x048
  29#define SYS_FLASH               0x04c
  30#define SYS_CFGSW               0x058
  31#define SYS_24MHZ               0x05c
  32#define SYS_MISC                0x060
  33#define SYS_DMA                 0x064
  34#define SYS_PROCID0             0x084
  35#define SYS_PROCID1             0x088
  36#define SYS_CFGDATA             0x0a0
  37#define SYS_CFGCTRL             0x0a4
  38#define SYS_CFGSTAT             0x0a8
  39
  40#define SYS_HBI_MASK            0xfff
  41#define SYS_PROCIDx_HBI_SHIFT   0
  42
  43#define SYS_MISC_MASTERSITE     (1 << 14)
  44
  45void vexpress_flags_set(u32 data)
  46{
  47        static void __iomem *base;
  48
  49        if (!base) {
  50                struct device_node *node = of_find_compatible_node(NULL, NULL,
  51                                "arm,vexpress-sysreg");
  52
  53                base = of_iomap(node, 0);
  54        }
  55
  56        if (WARN_ON(!base))
  57                return;
  58
  59        writel(~0, base + SYS_FLAGSCLR);
  60        writel(data, base + SYS_FLAGSSET);
  61}
  62
  63/* The sysreg block is just a random collection of various functions... */
  64
  65static struct syscon_platform_data vexpress_sysreg_sys_id_pdata = {
  66        .label = "sys_id",
  67};
  68
  69static struct bgpio_pdata vexpress_sysreg_sys_led_pdata = {
  70        .label = "sys_led",
  71        .base = -1,
  72        .ngpio = 8,
  73};
  74
  75static struct bgpio_pdata vexpress_sysreg_sys_mci_pdata = {
  76        .label = "sys_mci",
  77        .base = -1,
  78        .ngpio = 2,
  79};
  80
  81static struct bgpio_pdata vexpress_sysreg_sys_flash_pdata = {
  82        .label = "sys_flash",
  83        .base = -1,
  84        .ngpio = 1,
  85};
  86
  87static struct syscon_platform_data vexpress_sysreg_sys_misc_pdata = {
  88        .label = "sys_misc",
  89};
  90
  91static struct syscon_platform_data vexpress_sysreg_sys_procid_pdata = {
  92        .label = "sys_procid",
  93};
  94
  95static struct mfd_cell vexpress_sysreg_cells[] = {
  96        {
  97                .name = "syscon",
  98                .num_resources = 1,
  99                .resources = (struct resource []) {
 100                        DEFINE_RES_MEM(SYS_ID, 0x4),
 101                },
 102                .platform_data = &vexpress_sysreg_sys_id_pdata,
 103                .pdata_size = sizeof(vexpress_sysreg_sys_id_pdata),
 104        }, {
 105                .name = "basic-mmio-gpio",
 106                .of_compatible = "arm,vexpress-sysreg,sys_led",
 107                .num_resources = 1,
 108                .resources = (struct resource []) {
 109                        DEFINE_RES_MEM_NAMED(SYS_LED, 0x4, "dat"),
 110                },
 111                .platform_data = &vexpress_sysreg_sys_led_pdata,
 112                .pdata_size = sizeof(vexpress_sysreg_sys_led_pdata),
 113        }, {
 114                .name = "basic-mmio-gpio",
 115                .of_compatible = "arm,vexpress-sysreg,sys_mci",
 116                .num_resources = 1,
 117                .resources = (struct resource []) {
 118                        DEFINE_RES_MEM_NAMED(SYS_MCI, 0x4, "dat"),
 119                },
 120                .platform_data = &vexpress_sysreg_sys_mci_pdata,
 121                .pdata_size = sizeof(vexpress_sysreg_sys_mci_pdata),
 122        }, {
 123                .name = "basic-mmio-gpio",
 124                .of_compatible = "arm,vexpress-sysreg,sys_flash",
 125                .num_resources = 1,
 126                .resources = (struct resource []) {
 127                        DEFINE_RES_MEM_NAMED(SYS_FLASH, 0x4, "dat"),
 128                },
 129                .platform_data = &vexpress_sysreg_sys_flash_pdata,
 130                .pdata_size = sizeof(vexpress_sysreg_sys_flash_pdata),
 131        }, {
 132                .name = "syscon",
 133                .num_resources = 1,
 134                .resources = (struct resource []) {
 135                        DEFINE_RES_MEM(SYS_MISC, 0x4),
 136                },
 137                .platform_data = &vexpress_sysreg_sys_misc_pdata,
 138                .pdata_size = sizeof(vexpress_sysreg_sys_misc_pdata),
 139        }, {
 140                .name = "syscon",
 141                .num_resources = 1,
 142                .resources = (struct resource []) {
 143                        DEFINE_RES_MEM(SYS_PROCID0, 0x8),
 144                },
 145                .platform_data = &vexpress_sysreg_sys_procid_pdata,
 146                .pdata_size = sizeof(vexpress_sysreg_sys_procid_pdata),
 147        }, {
 148                .name = "vexpress-syscfg",
 149                .num_resources = 1,
 150                .resources = (struct resource []) {
 151                        DEFINE_RES_MEM(SYS_CFGDATA, 0xc),
 152                },
 153        }
 154};
 155
 156static int vexpress_sysreg_probe(struct platform_device *pdev)
 157{
 158        struct resource *mem;
 159        void __iomem *base;
 160        struct gpio_chip *mmc_gpio_chip;
 161        int master;
 162        u32 dt_hbi;
 163
 164        mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 165        if (!mem)
 166                return -EINVAL;
 167
 168        base = devm_ioremap(&pdev->dev, mem->start, resource_size(mem));
 169        if (!base)
 170                return -ENOMEM;
 171
 172        master = readl(base + SYS_MISC) & SYS_MISC_MASTERSITE ?
 173                        VEXPRESS_SITE_DB2 : VEXPRESS_SITE_DB1;
 174        vexpress_config_set_master(master);
 175
 176        /* Confirm board type against DT property, if available */
 177        if (of_property_read_u32(of_root, "arm,hbi", &dt_hbi) == 0) {
 178                u32 id = readl(base + (master == VEXPRESS_SITE_DB1 ?
 179                                 SYS_PROCID0 : SYS_PROCID1));
 180                u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
 181
 182                if (WARN_ON(dt_hbi != hbi))
 183                        dev_warn(&pdev->dev, "DT HBI (%x) is not matching hardware (%x)!\n",
 184                                        dt_hbi, hbi);
 185        }
 186
 187        /*
 188         * Duplicated SYS_MCI pseudo-GPIO controller for compatibility with
 189         * older trees using sysreg node for MMC control lines.
 190         */
 191        mmc_gpio_chip = devm_kzalloc(&pdev->dev, sizeof(*mmc_gpio_chip),
 192                        GFP_KERNEL);
 193        if (!mmc_gpio_chip)
 194                return -ENOMEM;
 195        bgpio_init(mmc_gpio_chip, &pdev->dev, 0x4, base + SYS_MCI,
 196                        NULL, NULL, NULL, NULL, 0);
 197        mmc_gpio_chip->ngpio = 2;
 198        gpiochip_add_data(mmc_gpio_chip, NULL);
 199
 200        return mfd_add_devices(&pdev->dev, PLATFORM_DEVID_AUTO,
 201                        vexpress_sysreg_cells,
 202                        ARRAY_SIZE(vexpress_sysreg_cells), mem, 0, NULL);
 203}
 204
 205static const struct of_device_id vexpress_sysreg_match[] = {
 206        { .compatible = "arm,vexpress-sysreg", },
 207        {},
 208};
 209
 210static struct platform_driver vexpress_sysreg_driver = {
 211        .driver = {
 212                .name = "vexpress-sysreg",
 213                .of_match_table = vexpress_sysreg_match,
 214        },
 215        .probe = vexpress_sysreg_probe,
 216};
 217
 218static int __init vexpress_sysreg_init(void)
 219{
 220        struct device_node *node;
 221
 222        /* Need the sysreg early, before any other device... */
 223        for_each_matching_node(node, vexpress_sysreg_match)
 224                of_platform_device_create(node, NULL, NULL);
 225
 226        return platform_driver_register(&vexpress_sysreg_driver);
 227}
 228core_initcall(vexpress_sysreg_init);
 229