xref: /linux/drivers/net/dsa/xrs700x/xrs700x_i2c.c (revision a68e9da48568a0adf5dc817ef81971c0d1aa0672)
1ee00b24fSGeorge McCollister // SPDX-License-Identifier: GPL-2.0
2ee00b24fSGeorge McCollister /*
3ee00b24fSGeorge McCollister  * Copyright (C) 2020 NovaTech LLC
4ee00b24fSGeorge McCollister  * George McCollister <george.mccollister@gmail.com>
5ee00b24fSGeorge McCollister  */
6ee00b24fSGeorge McCollister 
7ee00b24fSGeorge McCollister #include <linux/bits.h>
8ee00b24fSGeorge McCollister #include <linux/i2c.h>
9ee00b24fSGeorge McCollister #include <linux/module.h>
10ee00b24fSGeorge McCollister #include "xrs700x.h"
11ee00b24fSGeorge McCollister #include "xrs700x_reg.h"
12ee00b24fSGeorge McCollister 
13add285bcSTobias Waldekranz struct xrs700x_i2c_cmd {
14add285bcSTobias Waldekranz 	__be32 reg;
15add285bcSTobias Waldekranz 	__be16 val;
16add285bcSTobias Waldekranz } __packed;
17add285bcSTobias Waldekranz 
18ee00b24fSGeorge McCollister static int xrs700x_i2c_reg_read(void *context, unsigned int reg,
19ee00b24fSGeorge McCollister 				unsigned int *val)
20ee00b24fSGeorge McCollister {
21ee00b24fSGeorge McCollister 	struct device *dev = context;
22ee00b24fSGeorge McCollister 	struct i2c_client *i2c = to_i2c_client(dev);
23add285bcSTobias Waldekranz 	struct xrs700x_i2c_cmd cmd;
24ee00b24fSGeorge McCollister 	int ret;
25ee00b24fSGeorge McCollister 
26add285bcSTobias Waldekranz 	cmd.reg = cpu_to_be32(reg | 1);
27ee00b24fSGeorge McCollister 
28add285bcSTobias Waldekranz 	ret = i2c_master_send(i2c, (char *)&cmd.reg, sizeof(cmd.reg));
29ee00b24fSGeorge McCollister 	if (ret < 0) {
30ee00b24fSGeorge McCollister 		dev_err(dev, "xrs i2c_master_send returned %d\n", ret);
31ee00b24fSGeorge McCollister 		return ret;
32ee00b24fSGeorge McCollister 	}
33ee00b24fSGeorge McCollister 
34add285bcSTobias Waldekranz 	ret = i2c_master_recv(i2c, (char *)&cmd.val, sizeof(cmd.val));
35ee00b24fSGeorge McCollister 	if (ret < 0) {
36ee00b24fSGeorge McCollister 		dev_err(dev, "xrs i2c_master_recv returned %d\n", ret);
37ee00b24fSGeorge McCollister 		return ret;
38ee00b24fSGeorge McCollister 	}
39ee00b24fSGeorge McCollister 
40add285bcSTobias Waldekranz 	*val = be16_to_cpu(cmd.val);
41ee00b24fSGeorge McCollister 	return 0;
42ee00b24fSGeorge McCollister }
43ee00b24fSGeorge McCollister 
44ee00b24fSGeorge McCollister static int xrs700x_i2c_reg_write(void *context, unsigned int reg,
45ee00b24fSGeorge McCollister 				 unsigned int val)
46ee00b24fSGeorge McCollister {
47ee00b24fSGeorge McCollister 	struct device *dev = context;
48ee00b24fSGeorge McCollister 	struct i2c_client *i2c = to_i2c_client(dev);
49add285bcSTobias Waldekranz 	struct xrs700x_i2c_cmd cmd;
50ee00b24fSGeorge McCollister 	int ret;
51ee00b24fSGeorge McCollister 
52add285bcSTobias Waldekranz 	cmd.reg = cpu_to_be32(reg);
53add285bcSTobias Waldekranz 	cmd.val = cpu_to_be16(val);
54ee00b24fSGeorge McCollister 
55add285bcSTobias Waldekranz 	ret = i2c_master_send(i2c, (char *)&cmd, sizeof(cmd));
56ee00b24fSGeorge McCollister 	if (ret < 0) {
57ee00b24fSGeorge McCollister 		dev_err(dev, "xrs i2c_master_send returned %d\n", ret);
58ee00b24fSGeorge McCollister 		return ret;
59ee00b24fSGeorge McCollister 	}
60ee00b24fSGeorge McCollister 
61ee00b24fSGeorge McCollister 	return 0;
62ee00b24fSGeorge McCollister }
63ee00b24fSGeorge McCollister 
64ee00b24fSGeorge McCollister static const struct regmap_config xrs700x_i2c_regmap_config = {
65ee00b24fSGeorge McCollister 	.val_bits = 16,
66ee00b24fSGeorge McCollister 	.reg_stride = 2,
67ee00b24fSGeorge McCollister 	.reg_bits = 32,
68ee00b24fSGeorge McCollister 	.pad_bits = 0,
69ee00b24fSGeorge McCollister 	.write_flag_mask = 0,
70ee00b24fSGeorge McCollister 	.read_flag_mask = 0,
71ee00b24fSGeorge McCollister 	.reg_read = xrs700x_i2c_reg_read,
72ee00b24fSGeorge McCollister 	.reg_write = xrs700x_i2c_reg_write,
73ee00b24fSGeorge McCollister 	.max_register = 0,
74ee00b24fSGeorge McCollister 	.cache_type = REGCACHE_NONE,
75ee00b24fSGeorge McCollister 	.reg_format_endian = REGMAP_ENDIAN_BIG,
76ee00b24fSGeorge McCollister 	.val_format_endian = REGMAP_ENDIAN_BIG
77ee00b24fSGeorge McCollister };
78ee00b24fSGeorge McCollister 
79ee00b24fSGeorge McCollister static int xrs700x_i2c_probe(struct i2c_client *i2c,
80ee00b24fSGeorge McCollister 			     const struct i2c_device_id *i2c_id)
81ee00b24fSGeorge McCollister {
82ee00b24fSGeorge McCollister 	struct xrs700x *priv;
83ee00b24fSGeorge McCollister 	int ret;
84ee00b24fSGeorge McCollister 
85ee00b24fSGeorge McCollister 	priv = xrs700x_switch_alloc(&i2c->dev, i2c);
86ee00b24fSGeorge McCollister 	if (!priv)
87ee00b24fSGeorge McCollister 		return -ENOMEM;
88ee00b24fSGeorge McCollister 
89ee00b24fSGeorge McCollister 	priv->regmap = devm_regmap_init(&i2c->dev, NULL, &i2c->dev,
90ee00b24fSGeorge McCollister 					&xrs700x_i2c_regmap_config);
91ee00b24fSGeorge McCollister 	if (IS_ERR(priv->regmap)) {
92ee00b24fSGeorge McCollister 		ret = PTR_ERR(priv->regmap);
93ee00b24fSGeorge McCollister 		dev_err(&i2c->dev, "Failed to initialize regmap: %d\n", ret);
94ee00b24fSGeorge McCollister 		return ret;
95ee00b24fSGeorge McCollister 	}
96ee00b24fSGeorge McCollister 
97ee00b24fSGeorge McCollister 	i2c_set_clientdata(i2c, priv);
98ee00b24fSGeorge McCollister 
99ee00b24fSGeorge McCollister 	ret = xrs700x_switch_register(priv);
100ee00b24fSGeorge McCollister 
101ee00b24fSGeorge McCollister 	/* Main DSA driver may not be started yet. */
102ee00b24fSGeorge McCollister 	if (ret)
103ee00b24fSGeorge McCollister 		return ret;
104ee00b24fSGeorge McCollister 
105ee00b24fSGeorge McCollister 	return 0;
106ee00b24fSGeorge McCollister }
107ee00b24fSGeorge McCollister 
108ee00b24fSGeorge McCollister static int xrs700x_i2c_remove(struct i2c_client *i2c)
109ee00b24fSGeorge McCollister {
110ee00b24fSGeorge McCollister 	struct xrs700x *priv = i2c_get_clientdata(i2c);
111ee00b24fSGeorge McCollister 
112*a68e9da4SVladimir Oltean 	if (!priv)
113*a68e9da4SVladimir Oltean 		return 0;
114*a68e9da4SVladimir Oltean 
115ee00b24fSGeorge McCollister 	xrs700x_switch_remove(priv);
116ee00b24fSGeorge McCollister 
117*a68e9da4SVladimir Oltean 	i2c_set_clientdata(i2c, NULL);
118*a68e9da4SVladimir Oltean 
119ee00b24fSGeorge McCollister 	return 0;
120ee00b24fSGeorge McCollister }
121ee00b24fSGeorge McCollister 
122*a68e9da4SVladimir Oltean static void xrs700x_i2c_shutdown(struct i2c_client *i2c)
123*a68e9da4SVladimir Oltean {
124*a68e9da4SVladimir Oltean 	struct xrs700x *priv = i2c_get_clientdata(i2c);
125*a68e9da4SVladimir Oltean 
126*a68e9da4SVladimir Oltean 	if (!priv)
127*a68e9da4SVladimir Oltean 		return;
128*a68e9da4SVladimir Oltean 
129*a68e9da4SVladimir Oltean 	xrs700x_switch_shutdown(priv);
130*a68e9da4SVladimir Oltean 
131*a68e9da4SVladimir Oltean 	i2c_set_clientdata(i2c, NULL);
132*a68e9da4SVladimir Oltean }
133*a68e9da4SVladimir Oltean 
134ee00b24fSGeorge McCollister static const struct i2c_device_id xrs700x_i2c_id[] = {
135ee00b24fSGeorge McCollister 	{ "xrs700x-switch", 0 },
136ee00b24fSGeorge McCollister 	{},
137ee00b24fSGeorge McCollister };
138ee00b24fSGeorge McCollister 
139ee00b24fSGeorge McCollister MODULE_DEVICE_TABLE(i2c, xrs700x_i2c_id);
140ee00b24fSGeorge McCollister 
1413e0103a3SGeorge McCollister static const struct of_device_id __maybe_unused xrs700x_i2c_dt_ids[] = {
142ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7003e", .data = &xrs7003e_info },
143ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7003f", .data = &xrs7003f_info },
144ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7004e", .data = &xrs7004e_info },
145ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7004f", .data = &xrs7004f_info },
146ee00b24fSGeorge McCollister 	{},
147ee00b24fSGeorge McCollister };
148ee00b24fSGeorge McCollister MODULE_DEVICE_TABLE(of, xrs700x_i2c_dt_ids);
149ee00b24fSGeorge McCollister 
150ee00b24fSGeorge McCollister static struct i2c_driver xrs700x_i2c_driver = {
151ee00b24fSGeorge McCollister 	.driver = {
152ee00b24fSGeorge McCollister 		.name	= "xrs700x-i2c",
153ee00b24fSGeorge McCollister 		.of_match_table = of_match_ptr(xrs700x_i2c_dt_ids),
154ee00b24fSGeorge McCollister 	},
155ee00b24fSGeorge McCollister 	.probe	= xrs700x_i2c_probe,
156ee00b24fSGeorge McCollister 	.remove	= xrs700x_i2c_remove,
157*a68e9da4SVladimir Oltean 	.shutdown = xrs700x_i2c_shutdown,
158ee00b24fSGeorge McCollister 	.id_table = xrs700x_i2c_id,
159ee00b24fSGeorge McCollister };
160ee00b24fSGeorge McCollister 
161ee00b24fSGeorge McCollister module_i2c_driver(xrs700x_i2c_driver);
162ee00b24fSGeorge McCollister 
163ee00b24fSGeorge McCollister MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");
164ee00b24fSGeorge McCollister MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA I2C driver");
165ee00b24fSGeorge McCollister MODULE_LICENSE("GPL v2");
166