brintos

brintos / linux-shallow public Read only

0
0
Text · 3.7 KiB · 284ff4a Raw
149 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Theobroma Systems Mule I2C device multiplexer4 *5 * Copyright (C) 2024 Theobroma Systems Design und Consulting GmbH6 */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  0xff17#define MULE_I2C_MUX_DEFAULT_DEV 0x018 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 new77	 * mule fw. Mule fw without mux support will accept write ops to the78	 * 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");149