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/module.h> 18 #include <linux/of.h> 19 #include <linux/spi/spi.h> 20 21 static const struct mfd_cell altr_a10sr_subdev_info[] = { 22 { 23 .name = "altr_a10sr_gpio", 24 .of_compatible = "altr,a10sr-gpio", 25 }, 26 { 27 .name = "altr_a10sr_reset", 28 .of_compatible = "altr,a10sr-reset", 29 }, 30 }; 31 32 static bool altr_a10sr_reg_readable(struct device *dev, unsigned int reg) 33 { 34 switch (reg) { 35 case ALTR_A10SR_VERSION_READ: 36 case ALTR_A10SR_LED_REG: 37 case ALTR_A10SR_PBDSW_REG: 38 case ALTR_A10SR_PBDSW_IRQ_REG: 39 case ALTR_A10SR_PWR_GOOD1_REG: 40 case ALTR_A10SR_PWR_GOOD2_REG: 41 case ALTR_A10SR_PWR_GOOD3_REG: 42 case ALTR_A10SR_FMCAB_REG: 43 case ALTR_A10SR_HPS_RST_REG: 44 case ALTR_A10SR_USB_QSPI_REG: 45 case ALTR_A10SR_SFPA_REG: 46 case ALTR_A10SR_SFPB_REG: 47 case ALTR_A10SR_I2C_M_REG: 48 case ALTR_A10SR_WARM_RST_REG: 49 case ALTR_A10SR_WR_KEY_REG: 50 case ALTR_A10SR_PMBUS_REG: 51 return true; 52 default: 53 return false; 54 } 55 } 56 57 static bool altr_a10sr_reg_writeable(struct device *dev, unsigned int reg) 58 { 59 switch (reg) { 60 case ALTR_A10SR_LED_REG: 61 case ALTR_A10SR_PBDSW_IRQ_REG: 62 case ALTR_A10SR_FMCAB_REG: 63 case ALTR_A10SR_HPS_RST_REG: 64 case ALTR_A10SR_USB_QSPI_REG: 65 case ALTR_A10SR_SFPA_REG: 66 case ALTR_A10SR_SFPB_REG: 67 case ALTR_A10SR_WARM_RST_REG: 68 case ALTR_A10SR_WR_KEY_REG: 69 case ALTR_A10SR_PMBUS_REG: 70 return true; 71 default: 72 return false; 73 } 74 } 75 76 static bool altr_a10sr_reg_volatile(struct device *dev, unsigned int reg) 77 { 78 switch (reg) { 79 case ALTR_A10SR_PBDSW_REG: 80 case ALTR_A10SR_PBDSW_IRQ_REG: 81 case ALTR_A10SR_PWR_GOOD1_REG: 82 case ALTR_A10SR_PWR_GOOD2_REG: 83 case ALTR_A10SR_PWR_GOOD3_REG: 84 case ALTR_A10SR_HPS_RST_REG: 85 case ALTR_A10SR_I2C_M_REG: 86 case ALTR_A10SR_WARM_RST_REG: 87 case ALTR_A10SR_WR_KEY_REG: 88 case ALTR_A10SR_PMBUS_REG: 89 return true; 90 default: 91 return false; 92 } 93 } 94 95 static const struct regmap_config altr_a10sr_regmap_config = { 96 .reg_bits = 8, 97 .val_bits = 8, 98 99 .cache_type = REGCACHE_NONE, 100 101 .use_single_read = true, 102 .use_single_write = true, 103 .read_flag_mask = 1, 104 .write_flag_mask = 0, 105 106 .max_register = ALTR_A10SR_WR_KEY_REG, 107 .readable_reg = altr_a10sr_reg_readable, 108 .writeable_reg = altr_a10sr_reg_writeable, 109 .volatile_reg = altr_a10sr_reg_volatile, 110 111 }; 112 113 static int altr_a10sr_spi_probe(struct spi_device *spi) 114 { 115 int ret; 116 struct altr_a10sr *a10sr; 117 118 a10sr = devm_kzalloc(&spi->dev, sizeof(*a10sr), 119 GFP_KERNEL); 120 if (!a10sr) 121 return -ENOMEM; 122 123 spi->mode = SPI_MODE_3; 124 spi->bits_per_word = 8; 125 spi_setup(spi); 126 127 a10sr->dev = &spi->dev; 128 129 spi_set_drvdata(spi, a10sr); 130 131 a10sr->regmap = devm_regmap_init_spi(spi, &altr_a10sr_regmap_config); 132 if (IS_ERR(a10sr->regmap)) { 133 ret = PTR_ERR(a10sr->regmap); 134 dev_err(&spi->dev, "Failed to allocate register map: %d\n", 135 ret); 136 return ret; 137 } 138 139 ret = devm_mfd_add_devices(a10sr->dev, PLATFORM_DEVID_AUTO, 140 altr_a10sr_subdev_info, 141 ARRAY_SIZE(altr_a10sr_subdev_info), 142 NULL, 0, NULL); 143 if (ret) 144 dev_err(a10sr->dev, "Failed to register sub-devices: %d\n", 145 ret); 146 147 return ret; 148 } 149 150 static const struct of_device_id altr_a10sr_spi_of_match[] = { 151 { .compatible = "altr,a10sr" }, 152 { }, 153 }; 154 MODULE_DEVICE_TABLE(of, altr_a10sr_spi_of_match); 155 156 static const struct spi_device_id altr_a10sr_spi_ids[] = { 157 { .name = "a10sr" }, 158 { }, 159 }; 160 MODULE_DEVICE_TABLE(spi, altr_a10sr_spi_ids); 161 162 static struct spi_driver altr_a10sr_spi_driver = { 163 .probe = altr_a10sr_spi_probe, 164 .driver = { 165 .name = "altr_a10sr", 166 .of_match_table = of_match_ptr(altr_a10sr_spi_of_match), 167 }, 168 .id_table = altr_a10sr_spi_ids, 169 }; 170 builtin_driver(altr_a10sr_spi_driver, spi_register_driver) 171