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(dev: &spi->dev, size: 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, data: a10sr); |
130 | |
131 | a10sr->regmap = devm_regmap_init_spi(spi, &altr_a10sr_regmap_config); |
132 | if (IS_ERR(ptr: a10sr->regmap)) { |
133 | ret = PTR_ERR(ptr: 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(dev: a10sr->dev, PLATFORM_DEVID_AUTO, |
140 | cells: altr_a10sr_subdev_info, |
141 | ARRAY_SIZE(altr_a10sr_subdev_info), |
142 | NULL, irq_base: 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 = 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 | |