xrs700x_i2c.c (3713B)
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 13struct xrs700x_i2c_cmd { 14 __be32 reg; 15 __be16 val; 16} __packed; 17 18static 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 44static 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 64static 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 79static 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 108static 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 i2c_set_clientdata(i2c, NULL); 118 119 return 0; 120} 121 122static void xrs700x_i2c_shutdown(struct i2c_client *i2c) 123{ 124 struct xrs700x *priv = i2c_get_clientdata(i2c); 125 126 if (!priv) 127 return; 128 129 xrs700x_switch_shutdown(priv); 130 131 i2c_set_clientdata(i2c, NULL); 132} 133 134static const struct i2c_device_id xrs700x_i2c_id[] = { 135 { "xrs700x-switch", 0 }, 136 {}, 137}; 138 139MODULE_DEVICE_TABLE(i2c, xrs700x_i2c_id); 140 141static const struct of_device_id __maybe_unused xrs700x_i2c_dt_ids[] = { 142 { .compatible = "arrow,xrs7003e", .data = &xrs7003e_info }, 143 { .compatible = "arrow,xrs7003f", .data = &xrs7003f_info }, 144 { .compatible = "arrow,xrs7004e", .data = &xrs7004e_info }, 145 { .compatible = "arrow,xrs7004f", .data = &xrs7004f_info }, 146 {}, 147}; 148MODULE_DEVICE_TABLE(of, xrs700x_i2c_dt_ids); 149 150static struct i2c_driver xrs700x_i2c_driver = { 151 .driver = { 152 .name = "xrs700x-i2c", 153 .of_match_table = of_match_ptr(xrs700x_i2c_dt_ids), 154 }, 155 .probe = xrs700x_i2c_probe, 156 .remove = xrs700x_i2c_remove, 157 .shutdown = xrs700x_i2c_shutdown, 158 .id_table = xrs700x_i2c_id, 159}; 160 161module_i2c_driver(xrs700x_i2c_driver); 162 163MODULE_AUTHOR("George McCollister <george.mccollister@gmail.com>"); 164MODULE_DESCRIPTION("Arrow SpeedChips XRS700x DSA I2C driver"); 165MODULE_LICENSE("GPL v2");