1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Theobroma Systems Mule I2C device multiplexer 4 * 5 * Copyright (C) 2024 Theobroma Systems Design und Consulting GmbH 6 */ 7 8 #include <linux/i2c-mux.h> 9 #include <linux/i2c.h> 10 #include <linux/module.h> 11 #include <linux/of.h> 12 #include <linux/platform_device.h> 13 #include <linux/property.h> 14 #include <linux/regmap.h> 15 16 #define MULE_I2C_MUX_CONFIG_REG 0xff 17 #define MULE_I2C_MUX_DEFAULT_DEV 0x0 18 19 struct mule_i2c_reg_mux { 20 struct regmap *regmap; 21 }; 22 23 static int mule_i2c_mux_select(struct i2c_mux_core *muxc, u32 dev) 24 { 25 struct mule_i2c_reg_mux *mux = muxc->priv; 26 27 return regmap_write(mux->regmap, MULE_I2C_MUX_CONFIG_REG, dev); 28 } 29 30 static int mule_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 dev) 31 { 32 return mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV); 33 } 34 35 static void mule_i2c_mux_remove(void *data) 36 { 37 struct i2c_mux_core *muxc = data; 38 39 i2c_mux_del_adapters(muxc); 40 41 mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV); 42 } 43 44 static int mule_i2c_mux_probe(struct platform_device *pdev) 45 { 46 struct device *mux_dev = &pdev->dev; 47 struct mule_i2c_reg_mux *priv; 48 struct i2c_client *client; 49 struct i2c_mux_core *muxc; 50 struct device_node *dev; 51 unsigned int readback; 52 int ndev, ret; 53 bool old_fw; 54 55 /* Count devices on the mux */ 56 ndev = of_get_child_count(mux_dev->of_node); 57 dev_dbg(mux_dev, "%d devices on the mux\n", ndev); 58 59 client = to_i2c_client(mux_dev->parent); 60 61 muxc = i2c_mux_alloc(client->adapter, mux_dev, ndev, sizeof(*priv), 62 I2C_MUX_LOCKED, mule_i2c_mux_select, mule_i2c_mux_deselect); 63 if (!muxc) 64 return -ENOMEM; 65 66 priv = i2c_mux_priv(muxc); 67 68 priv->regmap = dev_get_regmap(mux_dev->parent, NULL); 69 if (!priv->regmap) 70 return dev_err_probe(mux_dev, -ENODEV, 71 "No parent i2c register map\n"); 72 73 platform_set_drvdata(pdev, muxc); 74 75 /* 76 * MULE_I2C_MUX_DEFAULT_DEV is guaranteed to exist on all old and new 77 * mule fw. Mule fw without mux support will accept write ops to the 78 * config register, but readback returns 0xff (register not updated). 79 */ 80 ret = mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV); 81 if (ret) 82 return dev_err_probe(mux_dev, ret, 83 "Failed to write config register\n"); 84 85 ret = regmap_read(priv->regmap, MULE_I2C_MUX_CONFIG_REG, &readback); 86 if (ret) 87 return dev_err_probe(mux_dev, ret, 88 "Failed to read config register\n"); 89 90 old_fw = (readback != MULE_I2C_MUX_DEFAULT_DEV); 91 92 ret = devm_add_action_or_reset(mux_dev, mule_i2c_mux_remove, muxc); 93 if (ret) 94 return dev_err_probe(mux_dev, ret, 95 "Failed to register mux remove\n"); 96 97 /* Create device adapters */ 98 for_each_child_of_node(mux_dev->of_node, dev) { 99 u32 reg; 100 101 ret = of_property_read_u32(dev, "reg", ®); 102 if (ret) 103 return dev_err_probe(mux_dev, ret, 104 "No reg property found for %s\n", 105 of_node_full_name(dev)); 106 107 if (old_fw && reg != 0) { 108 dev_warn(mux_dev, 109 "Mux is not supported, please update Mule FW\n"); 110 continue; 111 } 112 113 ret = mule_i2c_mux_select(muxc, reg); 114 if (ret) { 115 dev_warn(mux_dev, 116 "Device %d not supported, please update Mule FW\n", reg); 117 continue; 118 } 119 120 ret = i2c_mux_add_adapter(muxc, 0, reg); 121 if (ret) 122 return ret; 123 } 124 125 mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV); 126 127 return 0; 128 } 129 130 static const struct of_device_id mule_i2c_mux_of_match[] = { 131 { .compatible = "tsd,mule-i2c-mux", }, 132 {}, 133 }; 134 MODULE_DEVICE_TABLE(of, mule_i2c_mux_of_match); 135 136 static struct platform_driver mule_i2c_mux_driver = { 137 .driver = { 138 .name = "mule-i2c-mux", 139 .of_match_table = mule_i2c_mux_of_match, 140 }, 141 .probe = mule_i2c_mux_probe, 142 }; 143 144 module_platform_driver(mule_i2c_mux_driver); 145 146 MODULE_AUTHOR("Farouk Bouabid <farouk.bouabid@cherry.de>"); 147 MODULE_DESCRIPTION("I2C mux driver for Theobroma Systems Mule"); 148 MODULE_LICENSE("GPL"); 149