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