Commit | Line | Data |
---|---|---|
876611c4 XY |
1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* | |
3 | * Intel MAX 10 Board Management Controller chip | |
4 | * | |
5 | * Copyright (C) 2018-2020 Intel Corporation. All rights reserved. | |
6 | */ | |
7 | #include <linux/bitfield.h> | |
603aed8f | 8 | #include <linux/dev_printk.h> |
876611c4 XY |
9 | #include <linux/init.h> |
10 | #include <linux/mfd/core.h> | |
11 | #include <linux/mfd/intel-m10-bmc.h> | |
12 | #include <linux/module.h> | |
876611c4 XY |
13 | #include <linux/regmap.h> |
14 | #include <linux/spi/spi.h> | |
15 | ||
8169f74c MG |
16 | static const struct regmap_range m10bmc_regmap_range[] = { |
17 | regmap_reg_range(M10BMC_LEGACY_BUILD_VER, M10BMC_LEGACY_BUILD_VER), | |
18 | regmap_reg_range(M10BMC_SYS_BASE, M10BMC_SYS_END), | |
19 | regmap_reg_range(M10BMC_FLASH_BASE, M10BMC_FLASH_END), | |
20 | }; | |
21 | ||
22 | static const struct regmap_access_table m10bmc_access_table = { | |
23 | .yes_ranges = m10bmc_regmap_range, | |
24 | .n_yes_ranges = ARRAY_SIZE(m10bmc_regmap_range), | |
25 | }; | |
26 | ||
876611c4 XY |
27 | static struct regmap_config intel_m10bmc_regmap_config = { |
28 | .reg_bits = 32, | |
29 | .val_bits = 32, | |
30 | .reg_stride = 4, | |
8169f74c MG |
31 | .wr_table = &m10bmc_access_table, |
32 | .rd_table = &m10bmc_access_table, | |
876611c4 XY |
33 | .max_register = M10BMC_MEM_END, |
34 | }; | |
35 | ||
876611c4 XY |
36 | static int check_m10bmc_version(struct intel_m10bmc *ddata) |
37 | { | |
38 | unsigned int v; | |
39 | int ret; | |
40 | ||
41 | /* | |
5893f4d1 XY |
42 | * This check is to filter out the very old legacy BMC versions. In the |
43 | * old BMC chips, the BMC version info is stored in the old version | |
44 | * register (M10BMC_LEGACY_BUILD_VER), so its read out value would have | |
45 | * not been M10BMC_VER_LEGACY_INVALID (0xffffffff). But in new BMC | |
46 | * chips that the driver supports, the value of this register should be | |
47 | * M10BMC_VER_LEGACY_INVALID. | |
876611c4 | 48 | */ |
5893f4d1 | 49 | ret = m10bmc_raw_read(ddata, M10BMC_LEGACY_BUILD_VER, &v); |
876611c4 XY |
50 | if (ret) |
51 | return -ENODEV; | |
52 | ||
53 | if (v != M10BMC_VER_LEGACY_INVALID) { | |
54 | dev_err(ddata->dev, "bad version M10BMC detected\n"); | |
55 | return -ENODEV; | |
56 | } | |
57 | ||
58 | return 0; | |
59 | } | |
60 | ||
61 | static int intel_m10_bmc_spi_probe(struct spi_device *spi) | |
62 | { | |
63 | const struct spi_device_id *id = spi_get_device_id(spi); | |
16e5d95a | 64 | const struct intel_m10bmc_platform_info *info; |
876611c4 | 65 | struct device *dev = &spi->dev; |
876611c4 | 66 | struct intel_m10bmc *ddata; |
16e5d95a | 67 | int ret; |
876611c4 XY |
68 | |
69 | ddata = devm_kzalloc(dev, sizeof(*ddata), GFP_KERNEL); | |
70 | if (!ddata) | |
71 | return -ENOMEM; | |
72 | ||
16e5d95a | 73 | info = (struct intel_m10bmc_platform_info *)id->driver_data; |
876611c4 XY |
74 | ddata->dev = dev; |
75 | ||
603aed8f | 76 | ddata->regmap = devm_regmap_init_spi_avmm(spi, &intel_m10bmc_regmap_config); |
876611c4 XY |
77 | if (IS_ERR(ddata->regmap)) { |
78 | ret = PTR_ERR(ddata->regmap); | |
79 | dev_err(dev, "Failed to allocate regmap: %d\n", ret); | |
80 | return ret; | |
81 | } | |
82 | ||
83 | spi_set_drvdata(spi, ddata); | |
84 | ||
85 | ret = check_m10bmc_version(ddata); | |
86 | if (ret) { | |
87 | dev_err(dev, "Failed to identify m10bmc hardware\n"); | |
88 | return ret; | |
89 | } | |
90 | ||
603aed8f | 91 | return m10bmc_dev_init(ddata, info); |
876611c4 XY |
92 | } |
93 | ||
603aed8f IJ |
94 | static struct mfd_cell m10bmc_d5005_subdevs[] = { |
95 | { .name = "d5005bmc-hwmon" }, | |
96 | { .name = "d5005bmc-sec-update" }, | |
97 | }; | |
98 | ||
99 | static struct mfd_cell m10bmc_pacn3000_subdevs[] = { | |
100 | { .name = "n3000bmc-hwmon" }, | |
101 | { .name = "n3000bmc-retimer" }, | |
102 | { .name = "n3000bmc-sec-update" }, | |
103 | }; | |
104 | ||
105 | static struct mfd_cell m10bmc_n5010_subdevs[] = { | |
106 | { .name = "n5010bmc-hwmon" }, | |
107 | }; | |
108 | ||
16e5d95a IJ |
109 | static const struct intel_m10bmc_platform_info m10bmc_spi_n3000 = { |
110 | .cells = m10bmc_pacn3000_subdevs, | |
111 | .n_cells = ARRAY_SIZE(m10bmc_pacn3000_subdevs), | |
112 | }; | |
113 | ||
114 | static const struct intel_m10bmc_platform_info m10bmc_spi_d5005 = { | |
115 | .cells = m10bmc_d5005_subdevs, | |
116 | .n_cells = ARRAY_SIZE(m10bmc_d5005_subdevs), | |
117 | }; | |
118 | ||
119 | static const struct intel_m10bmc_platform_info m10bmc_spi_n5010 = { | |
120 | .cells = m10bmc_n5010_subdevs, | |
121 | .n_cells = ARRAY_SIZE(m10bmc_n5010_subdevs), | |
122 | }; | |
123 | ||
876611c4 | 124 | static const struct spi_device_id m10bmc_spi_id[] = { |
16e5d95a IJ |
125 | { "m10-n3000", (kernel_ulong_t)&m10bmc_spi_n3000 }, |
126 | { "m10-d5005", (kernel_ulong_t)&m10bmc_spi_d5005 }, | |
127 | { "m10-n5010", (kernel_ulong_t)&m10bmc_spi_n5010 }, | |
876611c4 XY |
128 | { } |
129 | }; | |
130 | MODULE_DEVICE_TABLE(spi, m10bmc_spi_id); | |
131 | ||
132 | static struct spi_driver intel_m10bmc_spi_driver = { | |
133 | .driver = { | |
134 | .name = "intel-m10-bmc", | |
603aed8f | 135 | .dev_groups = m10bmc_dev_groups, |
876611c4 XY |
136 | }, |
137 | .probe = intel_m10_bmc_spi_probe, | |
138 | .id_table = m10bmc_spi_id, | |
139 | }; | |
140 | module_spi_driver(intel_m10bmc_spi_driver); | |
141 | ||
603aed8f | 142 | MODULE_DESCRIPTION("Intel MAX 10 BMC SPI bus interface"); |
876611c4 XY |
143 | MODULE_AUTHOR("Intel Corporation"); |
144 | MODULE_LICENSE("GPL v2"); | |
145 | MODULE_ALIAS("spi:intel-m10-bmc"); |