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