xref: /openbmc/linux/drivers/mux/adg792a.c (revision 2612e3bbc0386368a850140a6c9b990cd496a5ec)
10edff03dSPeter Rosin // SPDX-License-Identifier: GPL-2.0
28f3addf1SPeter Rosin /*
38f3addf1SPeter Rosin  * Multiplexer driver for Analog Devices ADG792A/G Triple 4:1 mux
48f3addf1SPeter Rosin  *
58f3addf1SPeter Rosin  * Copyright (C) 2017 Axentia Technologies AB
68f3addf1SPeter Rosin  *
78f3addf1SPeter Rosin  * Author: Peter Rosin <peda@axentia.se>
88f3addf1SPeter Rosin  */
98f3addf1SPeter Rosin 
108f3addf1SPeter Rosin #include <linux/err.h>
118f3addf1SPeter Rosin #include <linux/i2c.h>
128f3addf1SPeter Rosin #include <linux/module.h>
138f3addf1SPeter Rosin #include <linux/mux/driver.h>
148f3addf1SPeter Rosin #include <linux/property.h>
158f3addf1SPeter Rosin 
168f3addf1SPeter Rosin #define ADG792A_LDSW		BIT(0)
178f3addf1SPeter Rosin #define ADG792A_RESETB		BIT(1)
188f3addf1SPeter Rosin #define ADG792A_DISABLE(mux)	(0x50 | (mux))
198f3addf1SPeter Rosin #define ADG792A_DISABLE_ALL	(0x5f)
208f3addf1SPeter Rosin #define ADG792A_MUX(mux, state)	(0xc0 | (((mux) + 1) << 2) | (state))
218f3addf1SPeter Rosin #define ADG792A_MUX_ALL(state)	(0xc0 | (state))
228f3addf1SPeter Rosin 
adg792a_write_cmd(struct i2c_client * i2c,u8 cmd,int reset)238f3addf1SPeter Rosin static int adg792a_write_cmd(struct i2c_client *i2c, u8 cmd, int reset)
248f3addf1SPeter Rosin {
258f3addf1SPeter Rosin 	u8 data = ADG792A_RESETB | ADG792A_LDSW;
268f3addf1SPeter Rosin 
278f3addf1SPeter Rosin 	/* ADG792A_RESETB is active low, the chip resets when it is zero. */
288f3addf1SPeter Rosin 	if (reset)
298f3addf1SPeter Rosin 		data &= ~ADG792A_RESETB;
308f3addf1SPeter Rosin 
318f3addf1SPeter Rosin 	return i2c_smbus_write_byte_data(i2c, cmd, data);
328f3addf1SPeter Rosin }
338f3addf1SPeter Rosin 
adg792a_set(struct mux_control * mux,int state)348f3addf1SPeter Rosin static int adg792a_set(struct mux_control *mux, int state)
358f3addf1SPeter Rosin {
368f3addf1SPeter Rosin 	struct i2c_client *i2c = to_i2c_client(mux->chip->dev.parent);
378f3addf1SPeter Rosin 	u8 cmd;
388f3addf1SPeter Rosin 
398f3addf1SPeter Rosin 	if (mux->chip->controllers == 1) {
408f3addf1SPeter Rosin 		/* parallel mux controller operation */
418f3addf1SPeter Rosin 		if (state == MUX_IDLE_DISCONNECT)
428f3addf1SPeter Rosin 			cmd = ADG792A_DISABLE_ALL;
438f3addf1SPeter Rosin 		else
448f3addf1SPeter Rosin 			cmd = ADG792A_MUX_ALL(state);
458f3addf1SPeter Rosin 	} else {
468f3addf1SPeter Rosin 		unsigned int controller = mux_control_get_index(mux);
478f3addf1SPeter Rosin 
488f3addf1SPeter Rosin 		if (state == MUX_IDLE_DISCONNECT)
498f3addf1SPeter Rosin 			cmd = ADG792A_DISABLE(controller);
508f3addf1SPeter Rosin 		else
518f3addf1SPeter Rosin 			cmd = ADG792A_MUX(controller, state);
528f3addf1SPeter Rosin 	}
538f3addf1SPeter Rosin 
548f3addf1SPeter Rosin 	return adg792a_write_cmd(i2c, cmd, 0);
558f3addf1SPeter Rosin }
568f3addf1SPeter Rosin 
578f3addf1SPeter Rosin static const struct mux_control_ops adg792a_ops = {
588f3addf1SPeter Rosin 	.set = adg792a_set,
598f3addf1SPeter Rosin };
608f3addf1SPeter Rosin 
adg792a_probe(struct i2c_client * i2c)612c363576SPeter Rosin static int adg792a_probe(struct i2c_client *i2c)
628f3addf1SPeter Rosin {
638f3addf1SPeter Rosin 	struct device *dev = &i2c->dev;
648f3addf1SPeter Rosin 	struct mux_chip *mux_chip;
658f3addf1SPeter Rosin 	s32 idle_state[3];
668f3addf1SPeter Rosin 	u32 cells;
678f3addf1SPeter Rosin 	int ret;
688f3addf1SPeter Rosin 	int i;
698f3addf1SPeter Rosin 
708f3addf1SPeter Rosin 	if (!i2c_check_functionality(i2c->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
718f3addf1SPeter Rosin 		return -ENODEV;
728f3addf1SPeter Rosin 
738f3addf1SPeter Rosin 	ret = device_property_read_u32(dev, "#mux-control-cells", &cells);
748f3addf1SPeter Rosin 	if (ret < 0)
758f3addf1SPeter Rosin 		return ret;
768f3addf1SPeter Rosin 	if (cells >= 2)
778f3addf1SPeter Rosin 		return -EINVAL;
788f3addf1SPeter Rosin 
798f3addf1SPeter Rosin 	mux_chip = devm_mux_chip_alloc(dev, cells ? 3 : 1, 0);
808f3addf1SPeter Rosin 	if (IS_ERR(mux_chip))
818f3addf1SPeter Rosin 		return PTR_ERR(mux_chip);
828f3addf1SPeter Rosin 
838f3addf1SPeter Rosin 	mux_chip->ops = &adg792a_ops;
848f3addf1SPeter Rosin 
858f3addf1SPeter Rosin 	ret = adg792a_write_cmd(i2c, ADG792A_DISABLE_ALL, 1);
868f3addf1SPeter Rosin 	if (ret < 0)
878f3addf1SPeter Rosin 		return ret;
888f3addf1SPeter Rosin 
898f3addf1SPeter Rosin 	ret = device_property_read_u32_array(dev, "idle-state",
908f3addf1SPeter Rosin 					     (u32 *)idle_state,
918f3addf1SPeter Rosin 					     mux_chip->controllers);
928f3addf1SPeter Rosin 	if (ret < 0) {
938f3addf1SPeter Rosin 		idle_state[0] = MUX_IDLE_AS_IS;
948f3addf1SPeter Rosin 		idle_state[1] = MUX_IDLE_AS_IS;
958f3addf1SPeter Rosin 		idle_state[2] = MUX_IDLE_AS_IS;
968f3addf1SPeter Rosin 	}
978f3addf1SPeter Rosin 
988f3addf1SPeter Rosin 	for (i = 0; i < mux_chip->controllers; ++i) {
998f3addf1SPeter Rosin 		struct mux_control *mux = &mux_chip->mux[i];
1008f3addf1SPeter Rosin 
1018f3addf1SPeter Rosin 		mux->states = 4;
1028f3addf1SPeter Rosin 
1038f3addf1SPeter Rosin 		switch (idle_state[i]) {
1048f3addf1SPeter Rosin 		case MUX_IDLE_DISCONNECT:
1058f3addf1SPeter Rosin 		case MUX_IDLE_AS_IS:
1068f3addf1SPeter Rosin 		case 0 ... 4:
1078f3addf1SPeter Rosin 			mux->idle_state = idle_state[i];
1088f3addf1SPeter Rosin 			break;
1098f3addf1SPeter Rosin 		default:
1108f3addf1SPeter Rosin 			dev_err(dev, "invalid idle-state %d\n", idle_state[i]);
1118f3addf1SPeter Rosin 			return -EINVAL;
1128f3addf1SPeter Rosin 		}
1138f3addf1SPeter Rosin 	}
1148f3addf1SPeter Rosin 
1158f3addf1SPeter Rosin 	ret = devm_mux_chip_register(dev, mux_chip);
1168f3addf1SPeter Rosin 	if (ret < 0)
1178f3addf1SPeter Rosin 		return ret;
1188f3addf1SPeter Rosin 
1198f3addf1SPeter Rosin 	if (cells)
1208f3addf1SPeter Rosin 		dev_info(dev, "3x single pole quadruple throw muxes registered\n");
1218f3addf1SPeter Rosin 	else
1228f3addf1SPeter Rosin 		dev_info(dev, "triple pole quadruple throw mux registered\n");
1238f3addf1SPeter Rosin 
1248f3addf1SPeter Rosin 	return 0;
1258f3addf1SPeter Rosin }
1268f3addf1SPeter Rosin 
1278f3addf1SPeter Rosin static const struct i2c_device_id adg792a_id[] = {
1288f3addf1SPeter Rosin 	{ .name = "adg792a", },
1298f3addf1SPeter Rosin 	{ .name = "adg792g", },
1308f3addf1SPeter Rosin 	{ }
1318f3addf1SPeter Rosin };
1328f3addf1SPeter Rosin MODULE_DEVICE_TABLE(i2c, adg792a_id);
1338f3addf1SPeter Rosin 
1348f3addf1SPeter Rosin static const struct of_device_id adg792a_of_match[] = {
1358f3addf1SPeter Rosin 	{ .compatible = "adi,adg792a", },
1368f3addf1SPeter Rosin 	{ .compatible = "adi,adg792g", },
1378f3addf1SPeter Rosin 	{ }
1388f3addf1SPeter Rosin };
1398f3addf1SPeter Rosin MODULE_DEVICE_TABLE(of, adg792a_of_match);
1408f3addf1SPeter Rosin 
1418f3addf1SPeter Rosin static struct i2c_driver adg792a_driver = {
1428f3addf1SPeter Rosin 	.driver		= {
1438f3addf1SPeter Rosin 		.name		= "adg792a",
1448f3addf1SPeter Rosin 		.of_match_table = of_match_ptr(adg792a_of_match),
1458f3addf1SPeter Rosin 	},
146*9f7b17c9SUwe Kleine-König 	.probe		= adg792a_probe,
1478f3addf1SPeter Rosin 	.id_table	= adg792a_id,
1488f3addf1SPeter Rosin };
1498f3addf1SPeter Rosin module_i2c_driver(adg792a_driver);
1508f3addf1SPeter Rosin 
1518f3addf1SPeter Rosin MODULE_DESCRIPTION("Analog Devices ADG792A/G Triple 4:1 mux driver");
1528f3addf1SPeter Rosin MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
1538f3addf1SPeter Rosin MODULE_LICENSE("GPL v2");
154