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