linux/drivers/mfd/altera-a10sr.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * Altera Arria10 DevKit System Resource MFD Driver
   4 *
   5 * Author: Thor Thayer <tthayer@opensource.altera.com>
   6 *
   7 * Copyright Intel Corporation (C) 2014-2016. All Rights Reserved
   8 *
   9 * SPI access for Altera Arria10 MAX5 System Resource Chip
  10 *
  11 * Adapted from DA9052
  12 */
  13
  14#include <linux/mfd/altera-a10sr.h>
  15#include <linux/mfd/core.h>
  16#include <linux/init.h>
  17#include <linux/of.h>
  18#include <linux/spi/spi.h>
  19
  20static const struct mfd_cell altr_a10sr_subdev_info[] = {
  21        {
  22                .name = "altr_a10sr_gpio",
  23                .of_compatible = "altr,a10sr-gpio",
  24        },
  25        {
  26                .name = "altr_a10sr_reset",
  27                .of_compatible = "altr,a10sr-reset",
  28        },
  29};
  30
  31static bool altr_a10sr_reg_readable(struct device *dev, unsigned int reg)
  32{
  33        switch (reg) {
  34        case ALTR_A10SR_VERSION_READ:
  35        case ALTR_A10SR_LED_REG:
  36        case ALTR_A10SR_PBDSW_REG:
  37        case ALTR_A10SR_PBDSW_IRQ_REG:
  38        case ALTR_A10SR_PWR_GOOD1_REG:
  39        case ALTR_A10SR_PWR_GOOD2_REG:
  40        case ALTR_A10SR_PWR_GOOD3_REG:
  41        case ALTR_A10SR_FMCAB_REG:
  42        case ALTR_A10SR_HPS_RST_REG:
  43        case ALTR_A10SR_USB_QSPI_REG:
  44        case ALTR_A10SR_SFPA_REG:
  45        case ALTR_A10SR_SFPB_REG:
  46        case ALTR_A10SR_I2C_M_REG:
  47        case ALTR_A10SR_WARM_RST_REG:
  48        case ALTR_A10SR_WR_KEY_REG:
  49        case ALTR_A10SR_PMBUS_REG:
  50                return true;
  51        default:
  52                return false;
  53        }
  54}
  55
  56static bool altr_a10sr_reg_writeable(struct device *dev, unsigned int reg)
  57{
  58        switch (reg) {
  59        case ALTR_A10SR_LED_REG:
  60        case ALTR_A10SR_PBDSW_IRQ_REG:
  61        case ALTR_A10SR_FMCAB_REG:
  62        case ALTR_A10SR_HPS_RST_REG:
  63        case ALTR_A10SR_USB_QSPI_REG:
  64        case ALTR_A10SR_SFPA_REG:
  65        case ALTR_A10SR_SFPB_REG:
  66        case ALTR_A10SR_WARM_RST_REG:
  67        case ALTR_A10SR_WR_KEY_REG:
  68        case ALTR_A10SR_PMBUS_REG:
  69                return true;
  70        default:
  71                return false;
  72        }
  73}
  74
  75static bool altr_a10sr_reg_volatile(struct device *dev, unsigned int reg)
  76{
  77        switch (reg) {
  78        case ALTR_A10SR_PBDSW_REG:
  79        case ALTR_A10SR_PBDSW_IRQ_REG:
  80        case ALTR_A10SR_PWR_GOOD1_REG:
  81        case ALTR_A10SR_PWR_GOOD2_REG:
  82        case ALTR_A10SR_PWR_GOOD3_REG:
  83        case ALTR_A10SR_HPS_RST_REG:
  84        case ALTR_A10SR_I2C_M_REG:
  85        case ALTR_A10SR_WARM_RST_REG:
  86        case ALTR_A10SR_WR_KEY_REG:
  87        case ALTR_A10SR_PMBUS_REG:
  88                return true;
  89        default:
  90                return false;
  91        }
  92}
  93
  94static const struct regmap_config altr_a10sr_regmap_config = {
  95        .reg_bits = 8,
  96        .val_bits = 8,
  97
  98        .cache_type = REGCACHE_NONE,
  99
 100        .use_single_read = true,
 101        .use_single_write = true,
 102        .read_flag_mask = 1,
 103        .write_flag_mask = 0,
 104
 105        .max_register = ALTR_A10SR_WR_KEY_REG,
 106        .readable_reg = altr_a10sr_reg_readable,
 107        .writeable_reg = altr_a10sr_reg_writeable,
 108        .volatile_reg = altr_a10sr_reg_volatile,
 109
 110};
 111
 112static int altr_a10sr_spi_probe(struct spi_device *spi)
 113{
 114        int ret;
 115        struct altr_a10sr *a10sr;
 116
 117        a10sr = devm_kzalloc(&spi->dev, sizeof(*a10sr),
 118                             GFP_KERNEL);
 119        if (!a10sr)
 120                return -ENOMEM;
 121
 122        spi->mode = SPI_MODE_3;
 123        spi->bits_per_word = 8;
 124        spi_setup(spi);
 125
 126        a10sr->dev = &spi->dev;
 127
 128        spi_set_drvdata(spi, a10sr);
 129
 130        a10sr->regmap = devm_regmap_init_spi(spi, &altr_a10sr_regmap_config);
 131        if (IS_ERR(a10sr->regmap)) {
 132                ret = PTR_ERR(a10sr->regmap);
 133                dev_err(&spi->dev, "Failed to allocate register map: %d\n",
 134                        ret);
 135                return ret;
 136        }
 137
 138        ret = devm_mfd_add_devices(a10sr->dev, PLATFORM_DEVID_AUTO,
 139                                   altr_a10sr_subdev_info,
 140                                   ARRAY_SIZE(altr_a10sr_subdev_info),
 141                                   NULL, 0, NULL);
 142        if (ret)
 143                dev_err(a10sr->dev, "Failed to register sub-devices: %d\n",
 144                        ret);
 145
 146        return ret;
 147}
 148
 149static const struct of_device_id altr_a10sr_spi_of_match[] = {
 150        { .compatible = "altr,a10sr" },
 151        { },
 152};
 153
 154static struct spi_driver altr_a10sr_spi_driver = {
 155        .probe = altr_a10sr_spi_probe,
 156        .driver = {
 157                .name = "altr_a10sr",
 158                .of_match_table = of_match_ptr(altr_a10sr_spi_of_match),
 159        },
 160};
 161builtin_driver(altr_a10sr_spi_driver, spi_register_driver)
 162