xref: /linux/drivers/net/dsa/xrs700x/xrs700x_i2c.c (revision a1ff5a7d78a036d6c2178ee5acd6ba4946243800)
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 
xrs700x_i2c_reg_read(void * context,unsigned int reg,unsigned int * val)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 
xrs700x_i2c_reg_write(void * context,unsigned int reg,unsigned int val)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 
xrs700x_i2c_probe(struct i2c_client * i2c)79dfd5e53dSUwe Kleine-König static int xrs700x_i2c_probe(struct i2c_client *i2c)
80ee00b24fSGeorge McCollister {
81ee00b24fSGeorge McCollister 	struct xrs700x *priv;
82ee00b24fSGeorge McCollister 	int ret;
83ee00b24fSGeorge McCollister 
84ee00b24fSGeorge McCollister 	priv = xrs700x_switch_alloc(&i2c->dev, i2c);
85ee00b24fSGeorge McCollister 	if (!priv)
86ee00b24fSGeorge McCollister 		return -ENOMEM;
87ee00b24fSGeorge McCollister 
88ee00b24fSGeorge McCollister 	priv->regmap = devm_regmap_init(&i2c->dev, NULL, &i2c->dev,
89ee00b24fSGeorge McCollister 					&xrs700x_i2c_regmap_config);
90ee00b24fSGeorge McCollister 	if (IS_ERR(priv->regmap)) {
91ee00b24fSGeorge McCollister 		ret = PTR_ERR(priv->regmap);
92ee00b24fSGeorge McCollister 		dev_err(&i2c->dev, "Failed to initialize regmap: %d\n", ret);
93ee00b24fSGeorge McCollister 		return ret;
94ee00b24fSGeorge McCollister 	}
95ee00b24fSGeorge McCollister 
96ee00b24fSGeorge McCollister 	i2c_set_clientdata(i2c, priv);
97ee00b24fSGeorge McCollister 
98ee00b24fSGeorge McCollister 	ret = xrs700x_switch_register(priv);
99ee00b24fSGeorge McCollister 
100ee00b24fSGeorge McCollister 	/* Main DSA driver may not be started yet. */
101ee00b24fSGeorge McCollister 	if (ret)
102ee00b24fSGeorge McCollister 		return ret;
103ee00b24fSGeorge McCollister 
104ee00b24fSGeorge McCollister 	return 0;
105ee00b24fSGeorge McCollister }
106ee00b24fSGeorge McCollister 
xrs700x_i2c_remove(struct i2c_client * i2c)107ed5c2f5fSUwe Kleine-König static void xrs700x_i2c_remove(struct i2c_client *i2c)
108ee00b24fSGeorge McCollister {
109ee00b24fSGeorge McCollister 	struct xrs700x *priv = i2c_get_clientdata(i2c);
110ee00b24fSGeorge McCollister 
111a68e9da4SVladimir Oltean 	if (!priv)
112ed5c2f5fSUwe Kleine-König 		return;
113a68e9da4SVladimir Oltean 
114ee00b24fSGeorge McCollister 	xrs700x_switch_remove(priv);
115ee00b24fSGeorge McCollister }
116ee00b24fSGeorge McCollister 
xrs700x_i2c_shutdown(struct i2c_client * i2c)117a68e9da4SVladimir Oltean static void xrs700x_i2c_shutdown(struct i2c_client *i2c)
118a68e9da4SVladimir Oltean {
119a68e9da4SVladimir Oltean 	struct xrs700x *priv = i2c_get_clientdata(i2c);
120a68e9da4SVladimir Oltean 
121a68e9da4SVladimir Oltean 	if (!priv)
122a68e9da4SVladimir Oltean 		return;
123a68e9da4SVladimir Oltean 
124a68e9da4SVladimir Oltean 	xrs700x_switch_shutdown(priv);
125a68e9da4SVladimir Oltean 
126a68e9da4SVladimir Oltean 	i2c_set_clientdata(i2c, NULL);
127a68e9da4SVladimir Oltean }
128a68e9da4SVladimir Oltean 
129ee00b24fSGeorge McCollister static const struct i2c_device_id xrs700x_i2c_id[] = {
130*a6a6a980SUwe Kleine-König 	{ "xrs700x-switch" },
131*a6a6a980SUwe Kleine-König 	{}
132ee00b24fSGeorge McCollister };
133ee00b24fSGeorge McCollister 
134ee00b24fSGeorge McCollister MODULE_DEVICE_TABLE(i2c, xrs700x_i2c_id);
135ee00b24fSGeorge McCollister 
1363e0103a3SGeorge McCollister static const struct of_device_id __maybe_unused xrs700x_i2c_dt_ids[] = {
137ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7003e", .data = &xrs7003e_info },
138ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7003f", .data = &xrs7003f_info },
139ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7004e", .data = &xrs7004e_info },
140ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7004f", .data = &xrs7004f_info },
141ee00b24fSGeorge McCollister 	{},
142ee00b24fSGeorge McCollister };
143ee00b24fSGeorge McCollister MODULE_DEVICE_TABLE(of, xrs700x_i2c_dt_ids);
144ee00b24fSGeorge McCollister 
145ee00b24fSGeorge McCollister static struct i2c_driver xrs700x_i2c_driver = {
146ee00b24fSGeorge McCollister 	.driver = {
147ee00b24fSGeorge McCollister 		.name	= "xrs700x-i2c",
148ee00b24fSGeorge McCollister 		.of_match_table = of_match_ptr(xrs700x_i2c_dt_ids),
149ee00b24fSGeorge McCollister 	},
1503ea903e2SUwe Kleine-König 	.probe = xrs700x_i2c_probe,
151ee00b24fSGeorge McCollister 	.remove	= xrs700x_i2c_remove,
152a68e9da4SVladimir Oltean 	.shutdown = xrs700x_i2c_shutdown,
153ee00b24fSGeorge McCollister 	.id_table = xrs700x_i2c_id,
154ee00b24fSGeorge McCollister };
155ee00b24fSGeorge McCollister 
156ee00b24fSGeorge McCollister module_i2c_driver(xrs700x_i2c_driver);
157ee00b24fSGeorge McCollister 
158ee00b24fSGeorge McCollister MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");
159ee00b24fSGeorge McCollister MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA I2C driver");
160ee00b24fSGeorge McCollister MODULE_LICENSE("GPL v2");
161