xref: /linux/drivers/net/dsa/xrs700x/xrs700x_i2c.c (revision ed5c2f5fd10dda07263f79f338a512c0f49f76f5)
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 
108*ed5c2f5fSUwe Kleine-König static void xrs700x_i2c_remove(struct i2c_client *i2c)
109ee00b24fSGeorge McCollister {
110ee00b24fSGeorge McCollister 	struct xrs700x *priv = i2c_get_clientdata(i2c);
111ee00b24fSGeorge McCollister 
112a68e9da4SVladimir Oltean 	if (!priv)
113*ed5c2f5fSUwe Kleine-König 		return;
114a68e9da4SVladimir Oltean 
115ee00b24fSGeorge McCollister 	xrs700x_switch_remove(priv);
116ee00b24fSGeorge McCollister 
117a68e9da4SVladimir Oltean 	i2c_set_clientdata(i2c, NULL);
118ee00b24fSGeorge McCollister }
119ee00b24fSGeorge McCollister 
120a68e9da4SVladimir Oltean static void xrs700x_i2c_shutdown(struct i2c_client *i2c)
121a68e9da4SVladimir Oltean {
122a68e9da4SVladimir Oltean 	struct xrs700x *priv = i2c_get_clientdata(i2c);
123a68e9da4SVladimir Oltean 
124a68e9da4SVladimir Oltean 	if (!priv)
125a68e9da4SVladimir Oltean 		return;
126a68e9da4SVladimir Oltean 
127a68e9da4SVladimir Oltean 	xrs700x_switch_shutdown(priv);
128a68e9da4SVladimir Oltean 
129a68e9da4SVladimir Oltean 	i2c_set_clientdata(i2c, NULL);
130a68e9da4SVladimir Oltean }
131a68e9da4SVladimir Oltean 
132ee00b24fSGeorge McCollister static const struct i2c_device_id xrs700x_i2c_id[] = {
133ee00b24fSGeorge McCollister 	{ "xrs700x-switch", 0 },
134ee00b24fSGeorge McCollister 	{},
135ee00b24fSGeorge McCollister };
136ee00b24fSGeorge McCollister 
137ee00b24fSGeorge McCollister MODULE_DEVICE_TABLE(i2c, xrs700x_i2c_id);
138ee00b24fSGeorge McCollister 
1393e0103a3SGeorge McCollister static const struct of_device_id __maybe_unused xrs700x_i2c_dt_ids[] = {
140ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7003e", .data = &xrs7003e_info },
141ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7003f", .data = &xrs7003f_info },
142ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7004e", .data = &xrs7004e_info },
143ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7004f", .data = &xrs7004f_info },
144ee00b24fSGeorge McCollister 	{},
145ee00b24fSGeorge McCollister };
146ee00b24fSGeorge McCollister MODULE_DEVICE_TABLE(of, xrs700x_i2c_dt_ids);
147ee00b24fSGeorge McCollister 
148ee00b24fSGeorge McCollister static struct i2c_driver xrs700x_i2c_driver = {
149ee00b24fSGeorge McCollister 	.driver = {
150ee00b24fSGeorge McCollister 		.name	= "xrs700x-i2c",
151ee00b24fSGeorge McCollister 		.of_match_table = of_match_ptr(xrs700x_i2c_dt_ids),
152ee00b24fSGeorge McCollister 	},
153ee00b24fSGeorge McCollister 	.probe	= xrs700x_i2c_probe,
154ee00b24fSGeorge McCollister 	.remove	= xrs700x_i2c_remove,
155a68e9da4SVladimir Oltean 	.shutdown = xrs700x_i2c_shutdown,
156ee00b24fSGeorge McCollister 	.id_table = xrs700x_i2c_id,
157ee00b24fSGeorge McCollister };
158ee00b24fSGeorge McCollister 
159ee00b24fSGeorge McCollister module_i2c_driver(xrs700x_i2c_driver);
160ee00b24fSGeorge McCollister 
161ee00b24fSGeorge McCollister MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");
162ee00b24fSGeorge McCollister MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA I2C driver");
163ee00b24fSGeorge McCollister MODULE_LICENSE("GPL v2");
164