1 // SPDX-License-Identifier: GPL-2.0-only
3 * Ampere Altra Family SMPro core driver
4 * Copyright (c) 2022, Ampere Computing LLC
8 #include <linux/kernel.h>
9 #include <linux/mfd/core.h>
10 #include <linux/module.h>
11 #include <linux/of_platform.h>
12 #include <linux/regmap.h>
14 /* Identification Registers */
15 #define MANUFACTURER_ID_REG 0x02
16 #define AMPERE_MANUFACTURER_ID 0xCD3A
18 #define CORE_CE_ERR_DATA 0x82
19 #define CORE_UE_ERR_DATA 0x85
20 #define MEM_CE_ERR_DATA 0x92
21 #define MEM_UE_ERR_DATA 0x95
22 #define PCIE_CE_ERR_DATA 0xC2
23 #define PCIE_UE_ERR_DATA 0xC5
24 #define OTHER_CE_ERR_DATA 0xD2
25 #define OTHER_UE_ERR_DATA 0xDA
27 static int smpro_core_write(void *context
, const void *data
, size_t count
)
29 struct device
*dev
= context
;
30 struct i2c_client
*i2c
= to_i2c_client(dev
);
33 ret
= i2c_master_send(i2c
, data
, count
);
34 if (unlikely(ret
!= count
))
35 return (ret
< 0) ? ret
: -EIO
;
40 static int smpro_core_read(void *context
, const void *reg
, size_t reg_size
,
41 void *val
, size_t val_size
)
43 struct device
*dev
= context
;
44 struct i2c_client
*i2c
= to_i2c_client(dev
);
45 struct i2c_msg xfer
[2];
49 xfer
[0].addr
= i2c
->addr
;
57 xfer
[1].addr
= i2c
->addr
;
58 xfer
[1].flags
= I2C_M_RD
;
59 xfer
[1].len
= val_size
;
62 ret
= i2c_transfer(i2c
->adapter
, xfer
, 2);
63 if (unlikely(ret
!= 2))
64 return (ret
< 0) ? ret
: -EIO
;
69 static const struct regmap_bus smpro_regmap_bus
= {
70 .read
= smpro_core_read
,
71 .write
= smpro_core_write
,
72 .val_format_endian_default
= REGMAP_ENDIAN_BIG
,
75 static bool smpro_core_readable_noinc_reg(struct device
*dev
, unsigned int reg
)
77 return (reg
== CORE_CE_ERR_DATA
|| reg
== CORE_UE_ERR_DATA
||
78 reg
== MEM_CE_ERR_DATA
|| reg
== MEM_UE_ERR_DATA
||
79 reg
== PCIE_CE_ERR_DATA
|| reg
== PCIE_UE_ERR_DATA
||
80 reg
== OTHER_CE_ERR_DATA
|| reg
== OTHER_UE_ERR_DATA
);
83 static const struct regmap_config smpro_regmap_config
= {
86 .readable_noinc_reg
= smpro_core_readable_noinc_reg
,
89 static const struct mfd_cell smpro_devs
[] = {
90 MFD_CELL_NAME("smpro-hwmon"),
91 MFD_CELL_NAME("smpro-errmon"),
92 MFD_CELL_NAME("smpro-misc"),
95 static int smpro_core_probe(struct i2c_client
*i2c
)
97 const struct regmap_config
*config
;
98 struct regmap
*regmap
;
102 config
= device_get_match_data(&i2c
->dev
);
106 regmap
= devm_regmap_init(&i2c
->dev
, &smpro_regmap_bus
, &i2c
->dev
, config
);
108 return PTR_ERR(regmap
);
110 ret
= regmap_read(regmap
, MANUFACTURER_ID_REG
, &val
);
114 if (val
!= AMPERE_MANUFACTURER_ID
)
117 return devm_mfd_add_devices(&i2c
->dev
, PLATFORM_DEVID_AUTO
,
118 smpro_devs
, ARRAY_SIZE(smpro_devs
), NULL
, 0, NULL
);
121 static const struct of_device_id smpro_core_of_match
[] = {
122 { .compatible
= "ampere,smpro", .data
= &smpro_regmap_config
},
125 MODULE_DEVICE_TABLE(of
, smpro_core_of_match
);
127 static struct i2c_driver smpro_core_driver
= {
128 .probe
= smpro_core_probe
,
130 .name
= "smpro-core",
131 .of_match_table
= smpro_core_of_match
,
134 module_i2c_driver(smpro_core_driver
);
136 MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>");
137 MODULE_DESCRIPTION("SMPRO CORE - I2C driver");
138 MODULE_LICENSE("GPL");