1*1dc24632SBjorn Andersson // SPDX-License-Identifier: GPL-2.0 2*1dc24632SBjorn Andersson /* 3*1dc24632SBjorn Andersson * Copyright (C) 2021-2022 Linaro Ltd. 4*1dc24632SBjorn Andersson * Copyright (C) 2018-2020 The Linux Foundation 5*1dc24632SBjorn Andersson */ 6*1dc24632SBjorn Andersson 7*1dc24632SBjorn Andersson #include <linux/bits.h> 8*1dc24632SBjorn Andersson #include <linux/i2c.h> 9*1dc24632SBjorn Andersson #include <linux/kernel.h> 10*1dc24632SBjorn Andersson #include <linux/module.h> 11*1dc24632SBjorn Andersson #include <linux/mutex.h> 12*1dc24632SBjorn Andersson #include <linux/regmap.h> 13*1dc24632SBjorn Andersson #include <linux/usb/typec_dp.h> 14*1dc24632SBjorn Andersson #include <linux/usb/typec_mux.h> 15*1dc24632SBjorn Andersson 16*1dc24632SBjorn Andersson #define FSA4480_SWITCH_ENABLE 0x04 17*1dc24632SBjorn Andersson #define FSA4480_SWITCH_SELECT 0x05 18*1dc24632SBjorn Andersson #define FSA4480_SWITCH_STATUS1 0x07 19*1dc24632SBjorn Andersson #define FSA4480_SLOW_L 0x08 20*1dc24632SBjorn Andersson #define FSA4480_SLOW_R 0x09 21*1dc24632SBjorn Andersson #define FSA4480_SLOW_MIC 0x0a 22*1dc24632SBjorn Andersson #define FSA4480_SLOW_SENSE 0x0b 23*1dc24632SBjorn Andersson #define FSA4480_SLOW_GND 0x0c 24*1dc24632SBjorn Andersson #define FSA4480_DELAY_L_R 0x0d 25*1dc24632SBjorn Andersson #define FSA4480_DELAY_L_MIC 0x0e 26*1dc24632SBjorn Andersson #define FSA4480_DELAY_L_SENSE 0x0f 27*1dc24632SBjorn Andersson #define FSA4480_DELAY_L_AGND 0x10 28*1dc24632SBjorn Andersson #define FSA4480_RESET 0x1e 29*1dc24632SBjorn Andersson #define FSA4480_MAX_REGISTER 0x1f 30*1dc24632SBjorn Andersson 31*1dc24632SBjorn Andersson #define FSA4480_ENABLE_DEVICE BIT(7) 32*1dc24632SBjorn Andersson #define FSA4480_ENABLE_SBU GENMASK(6, 5) 33*1dc24632SBjorn Andersson #define FSA4480_ENABLE_USB GENMASK(4, 3) 34*1dc24632SBjorn Andersson 35*1dc24632SBjorn Andersson #define FSA4480_SEL_SBU_REVERSE GENMASK(6, 5) 36*1dc24632SBjorn Andersson #define FSA4480_SEL_USB GENMASK(4, 3) 37*1dc24632SBjorn Andersson 38*1dc24632SBjorn Andersson struct fsa4480 { 39*1dc24632SBjorn Andersson struct i2c_client *client; 40*1dc24632SBjorn Andersson 41*1dc24632SBjorn Andersson /* used to serialize concurrent change requests */ 42*1dc24632SBjorn Andersson struct mutex lock; 43*1dc24632SBjorn Andersson 44*1dc24632SBjorn Andersson struct typec_switch_dev *sw; 45*1dc24632SBjorn Andersson struct typec_mux_dev *mux; 46*1dc24632SBjorn Andersson 47*1dc24632SBjorn Andersson struct regmap *regmap; 48*1dc24632SBjorn Andersson 49*1dc24632SBjorn Andersson u8 cur_enable; 50*1dc24632SBjorn Andersson u8 cur_select; 51*1dc24632SBjorn Andersson }; 52*1dc24632SBjorn Andersson 53*1dc24632SBjorn Andersson static const struct regmap_config fsa4480_regmap_config = { 54*1dc24632SBjorn Andersson .reg_bits = 8, 55*1dc24632SBjorn Andersson .val_bits = 8, 56*1dc24632SBjorn Andersson .max_register = FSA4480_MAX_REGISTER, 57*1dc24632SBjorn Andersson /* Accesses only done under fsa4480->lock */ 58*1dc24632SBjorn Andersson .disable_locking = true, 59*1dc24632SBjorn Andersson }; 60*1dc24632SBjorn Andersson 61*1dc24632SBjorn Andersson static int fsa4480_switch_set(struct typec_switch_dev *sw, 62*1dc24632SBjorn Andersson enum typec_orientation orientation) 63*1dc24632SBjorn Andersson { 64*1dc24632SBjorn Andersson struct fsa4480 *fsa = typec_switch_get_drvdata(sw); 65*1dc24632SBjorn Andersson u8 new_sel; 66*1dc24632SBjorn Andersson 67*1dc24632SBjorn Andersson mutex_lock(&fsa->lock); 68*1dc24632SBjorn Andersson new_sel = FSA4480_SEL_USB; 69*1dc24632SBjorn Andersson if (orientation == TYPEC_ORIENTATION_REVERSE) 70*1dc24632SBjorn Andersson new_sel |= FSA4480_SEL_SBU_REVERSE; 71*1dc24632SBjorn Andersson 72*1dc24632SBjorn Andersson if (new_sel == fsa->cur_select) 73*1dc24632SBjorn Andersson goto out_unlock; 74*1dc24632SBjorn Andersson 75*1dc24632SBjorn Andersson if (fsa->cur_enable & FSA4480_ENABLE_SBU) { 76*1dc24632SBjorn Andersson /* Disable SBU output while re-configuring the switch */ 77*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, 78*1dc24632SBjorn Andersson fsa->cur_enable & ~FSA4480_ENABLE_SBU); 79*1dc24632SBjorn Andersson 80*1dc24632SBjorn Andersson /* 35us to allow the SBU switch to turn off */ 81*1dc24632SBjorn Andersson usleep_range(35, 1000); 82*1dc24632SBjorn Andersson } 83*1dc24632SBjorn Andersson 84*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, new_sel); 85*1dc24632SBjorn Andersson fsa->cur_select = new_sel; 86*1dc24632SBjorn Andersson 87*1dc24632SBjorn Andersson if (fsa->cur_enable & FSA4480_ENABLE_SBU) { 88*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable); 89*1dc24632SBjorn Andersson 90*1dc24632SBjorn Andersson /* 15us to allow the SBU switch to turn on again */ 91*1dc24632SBjorn Andersson usleep_range(15, 1000); 92*1dc24632SBjorn Andersson } 93*1dc24632SBjorn Andersson 94*1dc24632SBjorn Andersson out_unlock: 95*1dc24632SBjorn Andersson mutex_unlock(&fsa->lock); 96*1dc24632SBjorn Andersson 97*1dc24632SBjorn Andersson return 0; 98*1dc24632SBjorn Andersson } 99*1dc24632SBjorn Andersson 100*1dc24632SBjorn Andersson static int fsa4480_mux_set(struct typec_mux_dev *mux, struct typec_mux_state *state) 101*1dc24632SBjorn Andersson { 102*1dc24632SBjorn Andersson struct fsa4480 *fsa = typec_mux_get_drvdata(mux); 103*1dc24632SBjorn Andersson u8 new_enable; 104*1dc24632SBjorn Andersson 105*1dc24632SBjorn Andersson mutex_lock(&fsa->lock); 106*1dc24632SBjorn Andersson 107*1dc24632SBjorn Andersson new_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB; 108*1dc24632SBjorn Andersson if (state->mode >= TYPEC_DP_STATE_A) 109*1dc24632SBjorn Andersson new_enable |= FSA4480_ENABLE_SBU; 110*1dc24632SBjorn Andersson 111*1dc24632SBjorn Andersson if (new_enable == fsa->cur_enable) 112*1dc24632SBjorn Andersson goto out_unlock; 113*1dc24632SBjorn Andersson 114*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, new_enable); 115*1dc24632SBjorn Andersson fsa->cur_enable = new_enable; 116*1dc24632SBjorn Andersson 117*1dc24632SBjorn Andersson if (new_enable & FSA4480_ENABLE_SBU) { 118*1dc24632SBjorn Andersson /* 15us to allow the SBU switch to turn off */ 119*1dc24632SBjorn Andersson usleep_range(15, 1000); 120*1dc24632SBjorn Andersson } 121*1dc24632SBjorn Andersson 122*1dc24632SBjorn Andersson out_unlock: 123*1dc24632SBjorn Andersson mutex_unlock(&fsa->lock); 124*1dc24632SBjorn Andersson 125*1dc24632SBjorn Andersson return 0; 126*1dc24632SBjorn Andersson } 127*1dc24632SBjorn Andersson 128*1dc24632SBjorn Andersson static int fsa4480_probe(struct i2c_client *client) 129*1dc24632SBjorn Andersson { 130*1dc24632SBjorn Andersson struct device *dev = &client->dev; 131*1dc24632SBjorn Andersson struct typec_switch_desc sw_desc = { }; 132*1dc24632SBjorn Andersson struct typec_mux_desc mux_desc = { }; 133*1dc24632SBjorn Andersson struct fsa4480 *fsa; 134*1dc24632SBjorn Andersson 135*1dc24632SBjorn Andersson fsa = devm_kzalloc(dev, sizeof(*fsa), GFP_KERNEL); 136*1dc24632SBjorn Andersson if (!fsa) 137*1dc24632SBjorn Andersson return -ENOMEM; 138*1dc24632SBjorn Andersson 139*1dc24632SBjorn Andersson fsa->client = client; 140*1dc24632SBjorn Andersson mutex_init(&fsa->lock); 141*1dc24632SBjorn Andersson 142*1dc24632SBjorn Andersson fsa->regmap = devm_regmap_init_i2c(client, &fsa4480_regmap_config); 143*1dc24632SBjorn Andersson if (IS_ERR(fsa->regmap)) 144*1dc24632SBjorn Andersson return dev_err_probe(dev, PTR_ERR(fsa->regmap), "failed to initialize regmap\n"); 145*1dc24632SBjorn Andersson 146*1dc24632SBjorn Andersson fsa->cur_enable = FSA4480_ENABLE_DEVICE | FSA4480_ENABLE_USB; 147*1dc24632SBjorn Andersson fsa->cur_select = FSA4480_SEL_USB; 148*1dc24632SBjorn Andersson 149*1dc24632SBjorn Andersson /* set default settings */ 150*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SLOW_L, 0x00); 151*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SLOW_R, 0x00); 152*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SLOW_MIC, 0x00); 153*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SLOW_SENSE, 0x00); 154*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SLOW_GND, 0x00); 155*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_DELAY_L_R, 0x00); 156*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_DELAY_L_MIC, 0x00); 157*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_DELAY_L_SENSE, 0x00); 158*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_DELAY_L_AGND, 0x09); 159*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SWITCH_SELECT, fsa->cur_select); 160*1dc24632SBjorn Andersson regmap_write(fsa->regmap, FSA4480_SWITCH_ENABLE, fsa->cur_enable); 161*1dc24632SBjorn Andersson 162*1dc24632SBjorn Andersson sw_desc.drvdata = fsa; 163*1dc24632SBjorn Andersson sw_desc.fwnode = dev_fwnode(dev); 164*1dc24632SBjorn Andersson sw_desc.set = fsa4480_switch_set; 165*1dc24632SBjorn Andersson 166*1dc24632SBjorn Andersson fsa->sw = typec_switch_register(dev, &sw_desc); 167*1dc24632SBjorn Andersson if (IS_ERR(fsa->sw)) 168*1dc24632SBjorn Andersson return dev_err_probe(dev, PTR_ERR(fsa->sw), "failed to register typec switch\n"); 169*1dc24632SBjorn Andersson 170*1dc24632SBjorn Andersson mux_desc.drvdata = fsa; 171*1dc24632SBjorn Andersson mux_desc.fwnode = dev_fwnode(dev); 172*1dc24632SBjorn Andersson mux_desc.set = fsa4480_mux_set; 173*1dc24632SBjorn Andersson 174*1dc24632SBjorn Andersson fsa->mux = typec_mux_register(dev, &mux_desc); 175*1dc24632SBjorn Andersson if (IS_ERR(fsa->mux)) { 176*1dc24632SBjorn Andersson typec_switch_unregister(fsa->sw); 177*1dc24632SBjorn Andersson return dev_err_probe(dev, PTR_ERR(fsa->mux), "failed to register typec mux\n"); 178*1dc24632SBjorn Andersson } 179*1dc24632SBjorn Andersson 180*1dc24632SBjorn Andersson i2c_set_clientdata(client, fsa); 181*1dc24632SBjorn Andersson return 0; 182*1dc24632SBjorn Andersson } 183*1dc24632SBjorn Andersson 184*1dc24632SBjorn Andersson static int fsa4480_remove(struct i2c_client *client) 185*1dc24632SBjorn Andersson { 186*1dc24632SBjorn Andersson struct fsa4480 *fsa = i2c_get_clientdata(client); 187*1dc24632SBjorn Andersson 188*1dc24632SBjorn Andersson typec_mux_unregister(fsa->mux); 189*1dc24632SBjorn Andersson typec_switch_unregister(fsa->sw); 190*1dc24632SBjorn Andersson 191*1dc24632SBjorn Andersson return 0; 192*1dc24632SBjorn Andersson } 193*1dc24632SBjorn Andersson 194*1dc24632SBjorn Andersson static const struct i2c_device_id fsa4480_table[] = { 195*1dc24632SBjorn Andersson { "fsa4480" }, 196*1dc24632SBjorn Andersson { } 197*1dc24632SBjorn Andersson }; 198*1dc24632SBjorn Andersson MODULE_DEVICE_TABLE(i2c, fsa4480_table); 199*1dc24632SBjorn Andersson 200*1dc24632SBjorn Andersson static const struct of_device_id fsa4480_of_table[] = { 201*1dc24632SBjorn Andersson { .compatible = "fcs,fsa4480" }, 202*1dc24632SBjorn Andersson { } 203*1dc24632SBjorn Andersson }; 204*1dc24632SBjorn Andersson MODULE_DEVICE_TABLE(of, fsa4480_of_table); 205*1dc24632SBjorn Andersson 206*1dc24632SBjorn Andersson static struct i2c_driver fsa4480_driver = { 207*1dc24632SBjorn Andersson .driver = { 208*1dc24632SBjorn Andersson .name = "fsa4480", 209*1dc24632SBjorn Andersson .of_match_table = fsa4480_of_table, 210*1dc24632SBjorn Andersson }, 211*1dc24632SBjorn Andersson .probe_new = fsa4480_probe, 212*1dc24632SBjorn Andersson .remove = fsa4480_remove, 213*1dc24632SBjorn Andersson .id_table = fsa4480_table, 214*1dc24632SBjorn Andersson }; 215*1dc24632SBjorn Andersson module_i2c_driver(fsa4480_driver); 216*1dc24632SBjorn Andersson 217*1dc24632SBjorn Andersson MODULE_DESCRIPTION("ON Semiconductor FSA4480 driver"); 218*1dc24632SBjorn Andersson MODULE_LICENSE("GPL v2"); 219