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