Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.6.
  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
 19struct mule_i2c_reg_mux {
 20	struct regmap *regmap;
 21};
 22
 23static 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
 30static 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
 35static 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
 44static 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", &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
130static const struct of_device_id mule_i2c_mux_of_match[] = {
131	{ .compatible = "tsd,mule-i2c-mux", },
132	{},
133};
134MODULE_DEVICE_TABLE(of, mule_i2c_mux_of_match);
135
136static 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
144module_platform_driver(mule_i2c_mux_driver);
145
146MODULE_AUTHOR("Farouk Bouabid <farouk.bouabid@cherry.de>");
147MODULE_DESCRIPTION("I2C mux driver for Theobroma Systems Mule");
148MODULE_LICENSE("GPL");