cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

i2c-mux-pinctrl.c (4786B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * I2C multiplexer using pinctrl API
      4 *
      5 * Copyright (c) 2012, NVIDIA CORPORATION.  All rights reserved.
      6 */
      7
      8#include <linux/i2c.h>
      9#include <linux/i2c-mux.h>
     10#include <linux/module.h>
     11#include <linux/pinctrl/consumer.h>
     12#include <linux/platform_device.h>
     13#include <linux/slab.h>
     14#include <linux/of.h>
     15#include "../../pinctrl/core.h"
     16
     17struct i2c_mux_pinctrl {
     18	struct pinctrl *pinctrl;
     19	struct pinctrl_state *states[];
     20};
     21
     22static int i2c_mux_pinctrl_select(struct i2c_mux_core *muxc, u32 chan)
     23{
     24	struct i2c_mux_pinctrl *mux = i2c_mux_priv(muxc);
     25
     26	return pinctrl_select_state(mux->pinctrl, mux->states[chan]);
     27}
     28
     29static int i2c_mux_pinctrl_deselect(struct i2c_mux_core *muxc, u32 chan)
     30{
     31	return i2c_mux_pinctrl_select(muxc, muxc->num_adapters);
     32}
     33
     34static struct i2c_adapter *i2c_mux_pinctrl_root_adapter(
     35	struct pinctrl_state *state)
     36{
     37	struct i2c_adapter *root = NULL;
     38	struct pinctrl_setting *setting;
     39	struct i2c_adapter *pin_root;
     40
     41	list_for_each_entry(setting, &state->settings, node) {
     42		pin_root = i2c_root_adapter(setting->pctldev->dev);
     43		if (!pin_root)
     44			return NULL;
     45		if (!root)
     46			root = pin_root;
     47		else if (root != pin_root)
     48			return NULL;
     49	}
     50
     51	return root;
     52}
     53
     54static struct i2c_adapter *i2c_mux_pinctrl_parent_adapter(struct device *dev)
     55{
     56	struct device_node *np = dev->of_node;
     57	struct device_node *parent_np;
     58	struct i2c_adapter *parent;
     59
     60	parent_np = of_parse_phandle(np, "i2c-parent", 0);
     61	if (!parent_np) {
     62		dev_err(dev, "Cannot parse i2c-parent\n");
     63		return ERR_PTR(-ENODEV);
     64	}
     65	parent = of_find_i2c_adapter_by_node(parent_np);
     66	of_node_put(parent_np);
     67	if (!parent)
     68		return ERR_PTR(-EPROBE_DEFER);
     69
     70	return parent;
     71}
     72
     73static int i2c_mux_pinctrl_probe(struct platform_device *pdev)
     74{
     75	struct device *dev = &pdev->dev;
     76	struct device_node *np = dev->of_node;
     77	struct i2c_mux_core *muxc;
     78	struct i2c_mux_pinctrl *mux;
     79	struct i2c_adapter *parent;
     80	struct i2c_adapter *root;
     81	int num_names, i, ret;
     82	const char *name;
     83
     84	num_names = of_property_count_strings(np, "pinctrl-names");
     85	if (num_names < 0) {
     86		dev_err(dev, "Cannot parse pinctrl-names: %d\n",
     87			num_names);
     88		return num_names;
     89	}
     90
     91	parent = i2c_mux_pinctrl_parent_adapter(dev);
     92	if (IS_ERR(parent))
     93		return PTR_ERR(parent);
     94
     95	muxc = i2c_mux_alloc(parent, dev, num_names,
     96			     struct_size(mux, states, num_names),
     97			     0, i2c_mux_pinctrl_select, NULL);
     98	if (!muxc) {
     99		ret = -ENOMEM;
    100		goto err_put_parent;
    101	}
    102	mux = i2c_mux_priv(muxc);
    103
    104	platform_set_drvdata(pdev, muxc);
    105
    106	mux->pinctrl = devm_pinctrl_get(dev);
    107	if (IS_ERR(mux->pinctrl)) {
    108		ret = PTR_ERR(mux->pinctrl);
    109		dev_err(dev, "Cannot get pinctrl: %d\n", ret);
    110		goto err_put_parent;
    111	}
    112
    113	for (i = 0; i < num_names; i++) {
    114		ret = of_property_read_string_index(np, "pinctrl-names", i,
    115						    &name);
    116		if (ret < 0) {
    117			dev_err(dev, "Cannot parse pinctrl-names: %d\n", ret);
    118			goto err_put_parent;
    119		}
    120
    121		mux->states[i] = pinctrl_lookup_state(mux->pinctrl, name);
    122		if (IS_ERR(mux->states[i])) {
    123			ret = PTR_ERR(mux->states[i]);
    124			dev_err(dev, "Cannot look up pinctrl state %s: %d\n",
    125				name, ret);
    126			goto err_put_parent;
    127		}
    128
    129		if (strcmp(name, "idle"))
    130			continue;
    131
    132		if (i != num_names - 1) {
    133			dev_err(dev, "idle state must be last\n");
    134			ret = -EINVAL;
    135			goto err_put_parent;
    136		}
    137		muxc->deselect = i2c_mux_pinctrl_deselect;
    138	}
    139
    140	root = i2c_root_adapter(&muxc->parent->dev);
    141
    142	muxc->mux_locked = true;
    143	for (i = 0; i < num_names; i++) {
    144		if (root != i2c_mux_pinctrl_root_adapter(mux->states[i])) {
    145			muxc->mux_locked = false;
    146			break;
    147		}
    148	}
    149	if (muxc->mux_locked)
    150		dev_info(dev, "mux-locked i2c mux\n");
    151
    152	/* Do not add any adapter for the idle state (if it's there at all). */
    153	for (i = 0; i < num_names - !!muxc->deselect; i++) {
    154		ret = i2c_mux_add_adapter(muxc, 0, i, 0);
    155		if (ret)
    156			goto err_del_adapter;
    157	}
    158
    159	return 0;
    160
    161err_del_adapter:
    162	i2c_mux_del_adapters(muxc);
    163err_put_parent:
    164	i2c_put_adapter(parent);
    165
    166	return ret;
    167}
    168
    169static int i2c_mux_pinctrl_remove(struct platform_device *pdev)
    170{
    171	struct i2c_mux_core *muxc = platform_get_drvdata(pdev);
    172
    173	i2c_mux_del_adapters(muxc);
    174	i2c_put_adapter(muxc->parent);
    175
    176	return 0;
    177}
    178
    179static const struct of_device_id i2c_mux_pinctrl_of_match[] = {
    180	{ .compatible = "i2c-mux-pinctrl", },
    181	{},
    182};
    183MODULE_DEVICE_TABLE(of, i2c_mux_pinctrl_of_match);
    184
    185static struct platform_driver i2c_mux_pinctrl_driver = {
    186	.driver	= {
    187		.name	= "i2c-mux-pinctrl",
    188		.of_match_table = of_match_ptr(i2c_mux_pinctrl_of_match),
    189	},
    190	.probe	= i2c_mux_pinctrl_probe,
    191	.remove	= i2c_mux_pinctrl_remove,
    192};
    193module_platform_driver(i2c_mux_pinctrl_driver);
    194
    195MODULE_DESCRIPTION("pinctrl-based I2C multiplexer driver");
    196MODULE_AUTHOR("Stephen Warren <swarren@nvidia.com>");
    197MODULE_LICENSE("GPL v2");
    198MODULE_ALIAS("platform:i2c-mux-pinctrl");