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