1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 2ac8498f0SPeter Rosin /* 3ac8498f0SPeter Rosin * General Purpose I2C multiplexer 4ac8498f0SPeter Rosin * 5ac8498f0SPeter Rosin * Copyright (C) 2017 Axentia Technologies AB 6ac8498f0SPeter Rosin * 7ac8498f0SPeter Rosin * Author: Peter Rosin <peda@axentia.se> 8ac8498f0SPeter Rosin */ 9ac8498f0SPeter Rosin 10ac8498f0SPeter Rosin #include <linux/i2c.h> 11ac8498f0SPeter Rosin #include <linux/i2c-mux.h> 12ac8498f0SPeter Rosin #include <linux/module.h> 13ac8498f0SPeter Rosin #include <linux/mux/consumer.h> 14ac8498f0SPeter Rosin #include <linux/of_device.h> 15ac8498f0SPeter Rosin #include <linux/platform_device.h> 16ac8498f0SPeter Rosin 17ac8498f0SPeter Rosin struct mux { 18ac8498f0SPeter Rosin struct mux_control *control; 19ac8498f0SPeter Rosin 20ac8498f0SPeter Rosin bool do_not_deselect; 21ac8498f0SPeter Rosin }; 22ac8498f0SPeter Rosin 23ac8498f0SPeter Rosin static int i2c_mux_select(struct i2c_mux_core *muxc, u32 chan) 24ac8498f0SPeter Rosin { 25ac8498f0SPeter Rosin struct mux *mux = i2c_mux_priv(muxc); 26ac8498f0SPeter Rosin int ret; 27ac8498f0SPeter Rosin 28ac8498f0SPeter Rosin ret = mux_control_select(mux->control, chan); 29ac8498f0SPeter Rosin mux->do_not_deselect = ret < 0; 30ac8498f0SPeter Rosin 31ac8498f0SPeter Rosin return ret; 32ac8498f0SPeter Rosin } 33ac8498f0SPeter Rosin 34ac8498f0SPeter Rosin static int i2c_mux_deselect(struct i2c_mux_core *muxc, u32 chan) 35ac8498f0SPeter Rosin { 36ac8498f0SPeter Rosin struct mux *mux = i2c_mux_priv(muxc); 37ac8498f0SPeter Rosin 38ac8498f0SPeter Rosin if (mux->do_not_deselect) 39ac8498f0SPeter Rosin return 0; 40ac8498f0SPeter Rosin 41ac8498f0SPeter Rosin return mux_control_deselect(mux->control); 42ac8498f0SPeter Rosin } 43ac8498f0SPeter Rosin 44ac8498f0SPeter Rosin static struct i2c_adapter *mux_parent_adapter(struct device *dev) 45ac8498f0SPeter Rosin { 46ac8498f0SPeter Rosin struct device_node *np = dev->of_node; 47ac8498f0SPeter Rosin struct device_node *parent_np; 48ac8498f0SPeter Rosin struct i2c_adapter *parent; 49ac8498f0SPeter Rosin 50ac8498f0SPeter Rosin parent_np = of_parse_phandle(np, "i2c-parent", 0); 51ac8498f0SPeter Rosin if (!parent_np) { 52ac8498f0SPeter Rosin dev_err(dev, "Cannot parse i2c-parent\n"); 53ac8498f0SPeter Rosin return ERR_PTR(-ENODEV); 54ac8498f0SPeter Rosin } 55ac8498f0SPeter Rosin parent = of_find_i2c_adapter_by_node(parent_np); 56ac8498f0SPeter Rosin of_node_put(parent_np); 57ac8498f0SPeter Rosin if (!parent) 58ac8498f0SPeter Rosin return ERR_PTR(-EPROBE_DEFER); 59ac8498f0SPeter Rosin 60ac8498f0SPeter Rosin return parent; 61ac8498f0SPeter Rosin } 62ac8498f0SPeter Rosin 63ac8498f0SPeter Rosin static const struct of_device_id i2c_mux_of_match[] = { 64ac8498f0SPeter Rosin { .compatible = "i2c-mux", }, 65ac8498f0SPeter Rosin {}, 66ac8498f0SPeter Rosin }; 67ac8498f0SPeter Rosin MODULE_DEVICE_TABLE(of, i2c_mux_of_match); 68ac8498f0SPeter Rosin 69ac8498f0SPeter Rosin static int i2c_mux_probe(struct platform_device *pdev) 70ac8498f0SPeter Rosin { 71ac8498f0SPeter Rosin struct device *dev = &pdev->dev; 72ac8498f0SPeter Rosin struct device_node *np = dev->of_node; 73ac8498f0SPeter Rosin struct device_node *child; 74ac8498f0SPeter Rosin struct i2c_mux_core *muxc; 75ac8498f0SPeter Rosin struct mux *mux; 76ac8498f0SPeter Rosin struct i2c_adapter *parent; 77ac8498f0SPeter Rosin int children; 78ac8498f0SPeter Rosin int ret; 79ac8498f0SPeter Rosin 80ac8498f0SPeter Rosin if (!np) 81ac8498f0SPeter Rosin return -ENODEV; 82ac8498f0SPeter Rosin 83ac8498f0SPeter Rosin mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); 84ac8498f0SPeter Rosin if (!mux) 85ac8498f0SPeter Rosin return -ENOMEM; 86ac8498f0SPeter Rosin 87ac8498f0SPeter Rosin mux->control = devm_mux_control_get(dev, NULL); 88432d159aSKrzysztof Kozlowski if (IS_ERR(mux->control)) 89432d159aSKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(mux->control), 90432d159aSKrzysztof Kozlowski "failed to get control-mux\n"); 91ac8498f0SPeter Rosin 92ac8498f0SPeter Rosin parent = mux_parent_adapter(dev); 93432d159aSKrzysztof Kozlowski if (IS_ERR(parent)) 94432d159aSKrzysztof Kozlowski return dev_err_probe(dev, PTR_ERR(parent), 95432d159aSKrzysztof Kozlowski "failed to get i2c-parent adapter\n"); 96ac8498f0SPeter Rosin 97ac8498f0SPeter Rosin children = of_get_child_count(np); 98ac8498f0SPeter Rosin 99ac8498f0SPeter Rosin muxc = i2c_mux_alloc(parent, dev, children, 0, 0, 100ac8498f0SPeter Rosin i2c_mux_select, i2c_mux_deselect); 101ac8498f0SPeter Rosin if (!muxc) { 102ac8498f0SPeter Rosin ret = -ENOMEM; 103ac8498f0SPeter Rosin goto err_parent; 104ac8498f0SPeter Rosin } 105ac8498f0SPeter Rosin muxc->priv = mux; 106ac8498f0SPeter Rosin 107ac8498f0SPeter Rosin platform_set_drvdata(pdev, muxc); 108ac8498f0SPeter Rosin 109ac8498f0SPeter Rosin muxc->mux_locked = of_property_read_bool(np, "mux-locked"); 110ac8498f0SPeter Rosin 111ac8498f0SPeter Rosin for_each_child_of_node(np, child) { 112ac8498f0SPeter Rosin u32 chan; 113ac8498f0SPeter Rosin 114ac8498f0SPeter Rosin ret = of_property_read_u32(child, "reg", &chan); 115ac8498f0SPeter Rosin if (ret < 0) { 11649d54abeSRob Herring dev_err(dev, "no reg property for node '%pOFn'\n", 11749d54abeSRob Herring child); 118ac8498f0SPeter Rosin goto err_children; 119ac8498f0SPeter Rosin } 120ac8498f0SPeter Rosin 121ac8498f0SPeter Rosin if (chan >= mux_control_states(mux->control)) { 122ac8498f0SPeter Rosin dev_err(dev, "invalid reg %u\n", chan); 123ac8498f0SPeter Rosin ret = -EINVAL; 124ac8498f0SPeter Rosin goto err_children; 125ac8498f0SPeter Rosin } 126ac8498f0SPeter Rosin 127ac8498f0SPeter Rosin ret = i2c_mux_add_adapter(muxc, 0, chan, 0); 128ac8498f0SPeter Rosin if (ret) 129ac8498f0SPeter Rosin goto err_children; 130ac8498f0SPeter Rosin } 131ac8498f0SPeter Rosin 132ac8498f0SPeter Rosin dev_info(dev, "%d-port mux on %s adapter\n", children, parent->name); 133ac8498f0SPeter Rosin 134ac8498f0SPeter Rosin return 0; 135ac8498f0SPeter Rosin 136ac8498f0SPeter Rosin err_children: 1376435319cSLiang He of_node_put(child); 138ac8498f0SPeter Rosin i2c_mux_del_adapters(muxc); 139ac8498f0SPeter Rosin err_parent: 140ac8498f0SPeter Rosin i2c_put_adapter(parent); 141ac8498f0SPeter Rosin 142ac8498f0SPeter Rosin return ret; 143ac8498f0SPeter Rosin } 144ac8498f0SPeter Rosin 145*e190a0c3SUwe Kleine-König static void i2c_mux_remove(struct platform_device *pdev) 146ac8498f0SPeter Rosin { 147ac8498f0SPeter Rosin struct i2c_mux_core *muxc = platform_get_drvdata(pdev); 148ac8498f0SPeter Rosin 149ac8498f0SPeter Rosin i2c_mux_del_adapters(muxc); 150ac8498f0SPeter Rosin i2c_put_adapter(muxc->parent); 151ac8498f0SPeter Rosin } 152ac8498f0SPeter Rosin 153ac8498f0SPeter Rosin static struct platform_driver i2c_mux_driver = { 154ac8498f0SPeter Rosin .probe = i2c_mux_probe, 155*e190a0c3SUwe Kleine-König .remove_new = i2c_mux_remove, 156ac8498f0SPeter Rosin .driver = { 157ac8498f0SPeter Rosin .name = "i2c-mux-gpmux", 158ac8498f0SPeter Rosin .of_match_table = i2c_mux_of_match, 159ac8498f0SPeter Rosin }, 160ac8498f0SPeter Rosin }; 161ac8498f0SPeter Rosin module_platform_driver(i2c_mux_driver); 162ac8498f0SPeter Rosin 163ac8498f0SPeter Rosin MODULE_DESCRIPTION("General Purpose I2C multiplexer driver"); 164ac8498f0SPeter Rosin MODULE_AUTHOR("Peter Rosin <peda@axentia.se>"); 165ac8498f0SPeter Rosin MODULE_LICENSE("GPL v2"); 166