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 { 81 struct xrs700x *priv; 82 int ret; 83 84 priv = xrs700x_switch_alloc(&i2c->dev, i2c); 85 if (!priv) 86 return -ENOMEM; 87 88 priv->regmap = devm_regmap_init(&i2c->dev, NULL, &i2c->dev, 89 &xrs700x_i2c_regmap_config); 90 if (IS_ERR(priv->regmap)) { 91 ret = PTR_ERR(priv->regmap); 92 dev_err(&i2c->dev, "Failed to initialize regmap: %d\n", ret); 93 return ret; 94 } 95 96 i2c_set_clientdata(i2c, priv); 97 98 ret = xrs700x_switch_register(priv); 99 100 /* Main DSA driver may not be started yet. */ 101 if (ret) 102 return ret; 103 104 return 0; 105 } 106 107 static void xrs700x_i2c_remove(struct i2c_client *i2c) 108 { 109 struct xrs700x *priv = i2c_get_clientdata(i2c); 110 111 if (!priv) 112 return; 113 114 xrs700x_switch_remove(priv); 115 } 116 117 static void xrs700x_i2c_shutdown(struct i2c_client *i2c) 118 { 119 struct xrs700x *priv = i2c_get_clientdata(i2c); 120 121 if (!priv) 122 return; 123 124 xrs700x_switch_shutdown(priv); 125 126 i2c_set_clientdata(i2c, NULL); 127 } 128 129 static const struct i2c_device_id xrs700x_i2c_id[] = { 130 { "xrs700x-switch", 0 }, 131 {}, 132 }; 133 134 MODULE_DEVICE_TABLE(i2c, xrs700x_i2c_id); 135 136 static const struct of_device_id __maybe_unused xrs700x_i2c_dt_ids[] = { 137 { .compatible = "arrow,xrs7003e", .data = &xrs7003e_info }, 138 { .compatible = "arrow,xrs7003f", .data = &xrs7003f_info }, 139 { .compatible = "arrow,xrs7004e", .data = &xrs7004e_info }, 140 { .compatible = "arrow,xrs7004f", .data = &xrs7004f_info }, 141 {}, 142 }; 143 MODULE_DEVICE_TABLE(of, xrs700x_i2c_dt_ids); 144 145 static struct i2c_driver xrs700x_i2c_driver = { 146 .driver = { 147 .name = "xrs700x-i2c", 148 .of_match_table = of_match_ptr(xrs700x_i2c_dt_ids), 149 }, 150 .probe_new = xrs700x_i2c_probe, 151 .remove = xrs700x_i2c_remove, 152 .shutdown = xrs700x_i2c_shutdown, 153 .id_table = xrs700x_i2c_id, 154 }; 155 156 module_i2c_driver(xrs700x_i2c_driver); 157 158 MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>"); 159 MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA I2C driver"); 160 MODULE_LICENSE("GPL v2"); 161