1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Ampere Altra Family SMPro core driver 4 * Copyright (c) 2022, Ampere Computing LLC 5 */ 6 7 #include <linux/i2c.h> 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> 13 14 /* Identification Registers */ 15 #define MANUFACTURER_ID_REG 0x02 16 #define AMPERE_MANUFACTURER_ID 0xCD3A 17 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 26 27 static int smpro_core_write(void *context, const void *data, size_t count) 28 { 29 struct device *dev = context; 30 struct i2c_client *i2c = to_i2c_client(dev); 31 int ret; 32 33 ret = i2c_master_send(i2c, data, count); 34 if (unlikely(ret != count)) 35 return (ret < 0) ? ret : -EIO; 36 37 return 0; 38 } 39 40 static int smpro_core_read(void *context, const void *reg, size_t reg_size, 41 void *val, size_t val_size) 42 { 43 struct device *dev = context; 44 struct i2c_client *i2c = to_i2c_client(dev); 45 struct i2c_msg xfer[2]; 46 unsigned char buf[2]; 47 int ret; 48 49 xfer[0].addr = i2c->addr; 50 xfer[0].flags = 0; 51 52 buf[0] = *(u8 *)reg; 53 buf[1] = val_size; 54 xfer[0].len = 2; 55 xfer[0].buf = buf; 56 57 xfer[1].addr = i2c->addr; 58 xfer[1].flags = I2C_M_RD; 59 xfer[1].len = val_size; 60 xfer[1].buf = val; 61 62 ret = i2c_transfer(i2c->adapter, xfer, 2); 63 if (unlikely(ret != 2)) 64 return (ret < 0) ? ret : -EIO; 65 66 return 0; 67 } 68 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, 73 }; 74 75 static bool smpro_core_readable_noinc_reg(struct device *dev, unsigned int reg) 76 { 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); 81 } 82 83 static const struct regmap_config smpro_regmap_config = { 84 .reg_bits = 8, 85 .val_bits = 16, 86 .readable_noinc_reg = smpro_core_readable_noinc_reg, 87 }; 88 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"), 93 }; 94 95 static int smpro_core_probe(struct i2c_client *i2c) 96 { 97 const struct regmap_config *config; 98 struct regmap *regmap; 99 unsigned int val; 100 int ret; 101 102 config = device_get_match_data(&i2c->dev); 103 if (!config) 104 return -EINVAL; 105 106 regmap = devm_regmap_init(&i2c->dev, &smpro_regmap_bus, &i2c->dev, config); 107 if (IS_ERR(regmap)) 108 return PTR_ERR(regmap); 109 110 ret = regmap_read(regmap, MANUFACTURER_ID_REG, &val); 111 if (ret) 112 return ret; 113 114 if (val != AMPERE_MANUFACTURER_ID) 115 return -ENODEV; 116 117 return devm_mfd_add_devices(&i2c->dev, PLATFORM_DEVID_AUTO, 118 smpro_devs, ARRAY_SIZE(smpro_devs), NULL, 0, NULL); 119 } 120 121 static const struct of_device_id smpro_core_of_match[] = { 122 { .compatible = "ampere,smpro", .data = &smpro_regmap_config }, 123 {} 124 }; 125 MODULE_DEVICE_TABLE(of, smpro_core_of_match); 126 127 static struct i2c_driver smpro_core_driver = { 128 .probe = smpro_core_probe, 129 .driver = { 130 .name = "smpro-core", 131 .of_match_table = smpro_core_of_match, 132 }, 133 }; 134 module_i2c_driver(smpro_core_driver); 135 136 MODULE_AUTHOR("Quan Nguyen <quan@os.amperecomputing.com>"); 137 MODULE_DESCRIPTION("SMPRO CORE - I2C driver"); 138 MODULE_LICENSE("GPL"); 139