xref: /linux/drivers/net/dsa/xrs700x/xrs700x_i2c.c (revision add285bce37720675af5b1873f71af8561d0e2fe)
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 
13*add285bcSTobias Waldekranz struct xrs700x_i2c_cmd {
14*add285bcSTobias Waldekranz 	__be32 reg;
15*add285bcSTobias Waldekranz 	__be16 val;
16*add285bcSTobias Waldekranz } __packed;
17*add285bcSTobias 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);
23*add285bcSTobias Waldekranz 	struct xrs700x_i2c_cmd cmd;
24ee00b24fSGeorge McCollister 	int ret;
25ee00b24fSGeorge McCollister 
26*add285bcSTobias Waldekranz 	cmd.reg = cpu_to_be32(reg | 1);
27ee00b24fSGeorge McCollister 
28*add285bcSTobias 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 
34*add285bcSTobias 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 
40*add285bcSTobias 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);
49*add285bcSTobias Waldekranz 	struct xrs700x_i2c_cmd cmd;
50ee00b24fSGeorge McCollister 	int ret;
51ee00b24fSGeorge McCollister 
52*add285bcSTobias Waldekranz 	cmd.reg = cpu_to_be32(reg);
53*add285bcSTobias Waldekranz 	cmd.val = cpu_to_be16(val);
54ee00b24fSGeorge McCollister 
55*add285bcSTobias 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 
112ee00b24fSGeorge McCollister 	xrs700x_switch_remove(priv);
113ee00b24fSGeorge McCollister 
114ee00b24fSGeorge McCollister 	return 0;
115ee00b24fSGeorge McCollister }
116ee00b24fSGeorge McCollister 
117ee00b24fSGeorge McCollister static const struct i2c_device_id xrs700x_i2c_id[] = {
118ee00b24fSGeorge McCollister 	{ "xrs700x-switch", 0 },
119ee00b24fSGeorge McCollister 	{},
120ee00b24fSGeorge McCollister };
121ee00b24fSGeorge McCollister 
122ee00b24fSGeorge McCollister MODULE_DEVICE_TABLE(i2c, xrs700x_i2c_id);
123ee00b24fSGeorge McCollister 
124ee00b24fSGeorge McCollister static const struct of_device_id xrs700x_i2c_dt_ids[] = {
125ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7003e", .data = &xrs7003e_info },
126ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7003f", .data = &xrs7003f_info },
127ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7004e", .data = &xrs7004e_info },
128ee00b24fSGeorge McCollister 	{ .compatible = "arrow,xrs7004f", .data = &xrs7004f_info },
129ee00b24fSGeorge McCollister 	{},
130ee00b24fSGeorge McCollister };
131ee00b24fSGeorge McCollister MODULE_DEVICE_TABLE(of, xrs700x_i2c_dt_ids);
132ee00b24fSGeorge McCollister 
133ee00b24fSGeorge McCollister static struct i2c_driver xrs700x_i2c_driver = {
134ee00b24fSGeorge McCollister 	.driver = {
135ee00b24fSGeorge McCollister 		.name	= "xrs700x-i2c",
136ee00b24fSGeorge McCollister 		.of_match_table = of_match_ptr(xrs700x_i2c_dt_ids),
137ee00b24fSGeorge McCollister 	},
138ee00b24fSGeorge McCollister 	.probe	= xrs700x_i2c_probe,
139ee00b24fSGeorge McCollister 	.remove	= xrs700x_i2c_remove,
140ee00b24fSGeorge McCollister 	.id_table = xrs700x_i2c_id,
141ee00b24fSGeorge McCollister };
142ee00b24fSGeorge McCollister 
143ee00b24fSGeorge McCollister module_i2c_driver(xrs700x_i2c_driver);
144ee00b24fSGeorge McCollister 
145ee00b24fSGeorge McCollister MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>");
146ee00b24fSGeorge McCollister MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA I2C driver");
147ee00b24fSGeorge McCollister MODULE_LICENSE("GPL v2");
148