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