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