// SPDX-License-Identifier: GPL-2.0-only #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* dp eq */ #define PS5169_DP_EQ0_REG 0x52 #define PS5169_DP_EQ0_MASK 0x70 #define PS5169_DP_EQ1_REG 0x5e #define PS5169_DP_EQ1_MASK 0x07 #define PS5169_DP_EQ_MAX 5 #define PS5169_DP_EQ_DEFAULT 0 static const struct ps5169_dp_eq { unsigned int eq0; /* 0x52 bit 6:4 */ unsigned int eq1; /* 0x5e bit 2:0 */ } dp_eq[] = { {0x00, 0x04}, /* 0:2db */ {0x10, 0x05}, /* 1:5.5db */ {0x20, 0x06}, /* 2:6.5db */ {0x30, 0x06}, /* 3:7.5db */ {0x40, 0x06}, /* 4:8db */ {0x50, 0x07}, /* 5:8.5db */ {0x60, 0x07}, /* 6:9.5db */ {0x70, 0x07}, /* 7:10db ??? */ }; #define PS5169_DP_EQ0_VAL(eq) dp_eq[eq].eq0 #define PS5169_DP_EQ1_VAL(eq) dp_eq[eq].eq1 /* dp gain */ #define PS5169_DP_GAIN_REG 0x5c #define PS5169_DP_GAIN_MASK BIT(4) #define PS5169_DP_GAIN_MAX 1 /* -0.9db */ #define PS5169_DP_GAIN_DEFAULT 0 /* 0 db */ /* usb tx eq */ #define PS5169_USB_TX_EQ0_REG 0x50 #define PS5169_USB_TX_EQ0_MASK 0x70 #define PS5169_USB_TX_EQ1_REG 0x5d #define PS5169_USB_TX_EQ1_MASK 0x70 #define PS5169_USB_TX_EQ2_REG 0x54 #define PS5169_USB_TX_EQ2_MASK 0xf0 #define PS5169_USB_TX_EQ_MAX 7 #define PS5169_USB_TX_EQ_DEFAULT 1 static const struct ps5169_usb_tx_eq { unsigned int eq0; /* 0x50 bit 6:4 */ unsigned int eq1; /* 0x5d bit 6:4 */ unsigned int eq2; /* 0x54 bit 7:4 */ } usb_tx_eq[] = { {0x00, 0x40, 0x00}, /* 0:2db */ {0x10, 0x50, 0x10}, /* 1:5.5db */ {0x20, 0x60, 0x10}, /* 2:6.5db */ {0x30, 0x60, 0x50}, /* 3:7.5db */ {0x40, 0x60, 0xc0}, /* 4:8db */ {0x50, 0x70, 0x50}, /* 5:8.5db */ {0x60, 0x70, 0xf0}, /* 6:9.5db */ {0x70, 0x70, 0xf0}, /* 7:10db ???? */ }; #define PS5169_USB_TX_EQ0_VAL(eq) usb_tx_eq[eq].eq0 #define PS5169_USB_TX_EQ1_VAL(eq) usb_tx_eq[eq].eq1 #define PS5169_USB_TX_EQ2_VAL(eq) usb_tx_eq[eq].eq2 /* usb tx gain */ #define PS5169_USB_TX_GAIN_REG 0x5c #define PS5169_USB_TX_GAIN_MASK BIT(0) #define PS5169_USB_TX_GAIN_MAX 1 /* -0.9db */ #define PS5169_USB_TX_GAIN_DEFAULT 0 /* 0db */ /* usb rx eq */ #define PS5169_USB_RX_EQ0_REG 0x51 #define PS5169_USB_RX_EQ0_MASK 0x70 #define PS5169_USB_RX_EQ1_REG 0x77 #define PS5169_USB_RX_EQ1_MASK 0xf0 #define PS5169_USB_RX_EQ2_REG 0x54 #define PS5169_USB_RX_EQ2_MASK 0x0f #define PS5169_USB_RX_EQ3_REG 0x78 #define PS5169_USB_RX_EQ3_MASK 0xe1 #define PS5169_USB_RX_EQ_MAX 7 static const struct ps5169_usb_rx_eq { unsigned int eq0; /* 0x51 bit 7:4 2:1 */ unsigned int eq1; /* 0x77 bit 7:4 */ unsigned int eq2; /* 0x54 bit 3:0 */ unsigned int eq3; /* 0x78 bit 7:5 0 */ } usb_rx_eq[] = { {0x86, 0x00, 0x00, 0x20}, /* 0:5.2db */ {0x96, 0x00, 0x01, 0x20}, /* 1:6db */ {0xa6, 0x50, 0x01, 0x40}, /* 2:7db */ {0xb6, 0x50, 0x05, 0x40}, /* 3:8db */ {0xc6, 0xb0, 0x0c, 0x80}, /* 4:8.8db */ {0xd6, 0xf0, 0x05, 0x80}, /* 5:9.6db */ {0xe6, 0xf0, 0x0f, 0x80}, /* 6:10.4db */ {0xf6, 0x30, 0x0f, 0xa1}, /* 7:11.2db */ }; #define PS5169_USB_RX_EQ0_VAL(eq) usb_rx_eq[eq].eq0 #define PS5169_USB_RX_EQ1_VAL(eq) usb_rx_eq[eq].eq1 #define PS5169_USB_RX_EQ2_VAL(eq) usb_rx_eq[eq].eq2 #define PS5169_USB_RX_EQ3_VAL(eq) usb_rx_eq[eq].eq3 /* usb rx gain */ #define PS5169_USB_RX_GAIN_REG 0x5c #define PS5169_USB_RX_GAIN_MASK BIT(2) #define PS5169_USB_RX_GAIN_MAX 1 /* -0.9db */ #define PS5169_USB_RX_GAIN_DEFAULT 0 /* 0db */ /* configuration */ #define PS5169_CONFIG_REG 0x40 #define PS5169_CONFIG_REG_DEFAULT 0x40 #define PS5169_PD_ACTIVE BIT(7) #define PS5169_USB3_EN BIT(6) #define PS5169_DP_EN BIT(5) #define PS5169_FLIPPED BIT(4) #define PS5169_EMODE BIT(3) /* chip id */ #define PS5169_CHIPID_REG 0xAC #define PS5169_CHIP_ID 0x6987 enum operation_mode { OP_MODE_NONE, /* 4 lanes disabled */ OP_MODE_USB3, /* 2 lanes for USB and 2 lanes disabled */ OP_MODE_DP, /* 4 lanes DP */ OP_MODE_USB3_AND_DP, /* 2 lanes for USB and 2 lanes DP */ OP_MODE_DEFAULT, /* 4 lanes USB */ }; #define NOTIFIER_PRIORITY 1 struct ps5169_redriver { struct usb_redriver r; struct device *dev; struct i2c_client *client; struct regulator *vcc; struct regulator *vio; struct regmap *regmap; struct reg_sequence *config_seqs; unsigned int config_seqs_cnt; struct dentry *debug_root; /* tuning purpose */ unsigned int dpeq; unsigned int dpgain; unsigned int usbtxeq; unsigned int usbtxgain; unsigned int usbrxeq; unsigned int usbrxgain; int typec_orientation; enum operation_mode op_mode; int orientation_gpio; int enable_gpio; struct work_struct pullup_work; bool work_ongoing; struct work_struct host_work; }; static const char * const opmode_string[] = { [OP_MODE_NONE] = "NONE", [OP_MODE_USB3] = "USB3", [OP_MODE_DP] = "DP", [OP_MODE_USB3_AND_DP] = "USB3 and DP", [OP_MODE_DEFAULT] = "DEFAULT", }; #define OPMODESTR(x) opmode_string[x] static inline int ps5169_redriver_write_reg_bits(struct ps5169_redriver *ps5169, unsigned int reg, unsigned int val, unsigned int mask); static void ps5169_config_work_mode(struct ps5169_redriver *ps5169, enum operation_mode mode); static int ps5169_config_seqs_init(struct ps5169_redriver *ps5169); static int ps5169_redriver_enable_chip(struct ps5169_redriver *ps5169, bool en) { if (!gpio_is_valid(ps5169->enable_gpio)) { dev_err(ps5169->dev, "%s: Invalid enable_gpio: %d\n", __func__, ps5169->enable_gpio); return -EINVAL; } gpio_set_value(ps5169->enable_gpio, en); if (en) mdelay(10); return 0; } static int ps5169_get_orientation(struct usb_redriver *r) { struct ps5169_redriver *ps5169 = container_of(r, struct ps5169_redriver, r); int orientation; dev_dbg(ps5169->dev, "%s: mode %s\n", __func__, OPMODESTR(ps5169->op_mode)); if (!gpio_is_valid(ps5169->orientation_gpio)) orientation = 0; else orientation = gpio_get_value(ps5169->orientation_gpio); dev_info(ps5169->dev, "%s: mode %s, orientation %d\n", __func__, OPMODESTR(ps5169->op_mode), orientation); return orientation; } static int ps5169_notify_connect(struct usb_redriver *r, int ort) { struct ps5169_redriver *ps5169 = container_of(r, struct ps5169_redriver, r); enum operation_mode mode = ps5169->op_mode; if (ps5169->op_mode == OP_MODE_NONE) mode = OP_MODE_USB3; dev_info(ps5169->dev, "%s: op mode %s -> %s, orientation %s\n", __func__, OPMODESTR(ps5169->op_mode), OPMODESTR(mode), ort == ORIENTATION_CC1 ? "CC1" : "CC2"); ps5169->op_mode = mode; ps5169->typec_orientation = ort; ps5169_redriver_enable_chip(ps5169, true); ps5169_config_seqs_init(ps5169); ps5169_config_work_mode(ps5169, ps5169->op_mode); return 0; } static int ps5169_notify_disconnect(struct usb_redriver *r) { struct ps5169_redriver *ps5169 = container_of(r, struct ps5169_redriver, r); if (ps5169->op_mode == OP_MODE_NONE) return 0; dev_info(ps5169->dev, "%s: op mode %s -> %s\n", __func__, OPMODESTR(ps5169->op_mode), OPMODESTR(OP_MODE_NONE)); ps5169->op_mode = OP_MODE_NONE; ps5169_redriver_enable_chip(ps5169, false); return 0; } static int ps5169_release_usb_lanes(struct usb_redriver *r, int ort, int num) { struct ps5169_redriver *ps5169 = container_of(r, struct ps5169_redriver, r); enum operation_mode mode = ps5169->op_mode; if (num == 4) mode = OP_MODE_DP; else if (num == 2) mode = OP_MODE_USB3_AND_DP; else mode = ps5169->op_mode; ps5169->typec_orientation = ort; if (mode != ps5169->op_mode) { dev_info(ps5169->dev, "%s: op mode %s -> %s\n", __func__, OPMODESTR(ps5169->op_mode), OPMODESTR(mode)); ps5169->op_mode = mode; ps5169_redriver_enable_chip(ps5169, true); ps5169_config_seqs_init(ps5169); ps5169_config_work_mode(ps5169, mode); } return 0; } static void ps5169_gadget_pullup_work(struct work_struct *w) { struct ps5169_redriver *ps5169 = container_of(w, struct ps5169_redriver, pullup_work); ps5169_redriver_enable_chip(ps5169, false); usleep_range(1000, 1500); ps5169_redriver_enable_chip(ps5169, true); ps5169_config_seqs_init(ps5169); ps5169_config_work_mode(ps5169, ps5169->op_mode); ps5169->work_ongoing = false; } static int ps5169_gadget_pullup_enter(struct usb_redriver *r, int is_on) { struct ps5169_redriver *ps5169 = container_of(r, struct ps5169_redriver, r); u64 time = 0; dev_info(ps5169->dev, "%s: mode %s, %d, %d\n", __func__, OPMODESTR(ps5169->op_mode), is_on, ps5169->work_ongoing); if (ps5169->op_mode != OP_MODE_USB3) return -EINVAL; if (!is_on) return 0; while (ps5169->work_ongoing) { udelay(1); if (time++ > 500000) { dev_warn(ps5169->dev, "pullup timeout\n"); break; } } dev_info(ps5169->dev, "pull-up disable work took %llu us\n", time); return 0; } static int ps5169_gadget_pullup_exit(struct usb_redriver *r, int is_on) { struct ps5169_redriver *ps5169 = container_of(r, struct ps5169_redriver, r); dev_info(ps5169->dev, "%s: mode %s, %d, %d\n", __func__, OPMODESTR(ps5169->op_mode), is_on, ps5169->work_ongoing); if (ps5169->op_mode != OP_MODE_USB3) return -EINVAL; if (is_on) return 0; ps5169->work_ongoing = true; queue_work(system_highpri_wq, &ps5169->pullup_work); return 0; } static void ps5169_host_work(struct work_struct *w) { struct ps5169_redriver *ps5169 = container_of(w, struct ps5169_redriver, host_work); ps5169_redriver_enable_chip(ps5169, false); usleep_range(2000, 2500); ps5169_redriver_enable_chip(ps5169, true); ps5169_config_seqs_init(ps5169); ps5169_config_work_mode(ps5169, ps5169->op_mode); } static int ps5169_host_powercycle(struct usb_redriver *r) { struct ps5169_redriver *ps5169 = container_of(r, struct ps5169_redriver, r); if (ps5169->op_mode != OP_MODE_USB3) return -EINVAL; schedule_work(&ps5169->host_work); return 0; } static void ps5169_redriver_gpio_init(struct ps5169_redriver *ps5169) { struct device *dev = ps5169->dev; int rc; ps5169->orientation_gpio = of_get_named_gpio(dev->of_node, "redriver,orientation-gpio", 0); if (!gpio_is_valid(ps5169->orientation_gpio)) { dev_err(dev, "Failed to get orientation gpio\n"); return; } rc = devm_gpio_request(dev, ps5169->orientation_gpio, "redriver-orientation-gpio"); if (rc < 0) { dev_err(dev, "Failed to request orientation gpio\n"); ps5169->orientation_gpio = -EINVAL; return; } ps5169->r.has_orientation = true; ps5169->enable_gpio = of_get_named_gpio(dev->of_node, "redriver,enable-gpio", 0); if (!gpio_is_valid(ps5169->enable_gpio)) { dev_err(dev, "Failed to get enable gpio\n"); return; } rc = devm_gpio_request(dev, ps5169->enable_gpio, "redriver-enable-gpio"); if (rc < 0) { dev_err(dev, "Failed to request enable gpio\n"); ps5169->enable_gpio = -EINVAL; return; } gpio_direction_output(ps5169->enable_gpio, 0); } static inline int ps5169_redriver_write_reg_bits(struct ps5169_redriver *ps5169, unsigned int reg, unsigned int val, unsigned int mask) { int ret = regmap_update_bits(ps5169->regmap, reg, mask, val); if (ret < 0) dev_err(&ps5169->client->dev, "error update reg %u, ret=%d\n", reg, ret); dev_dbg(&ps5169->client->dev, "update reg[%u]=[%x], %x\n", reg, val, mask); return ret; } static int ps5169_config_dp_eq(struct ps5169_redriver *ps5169, unsigned int eq) { if (eq > PS5169_DP_EQ_MAX) { dev_err(&ps5169->client->dev, "error dp eq value %u\n", eq); return -EINVAL; } ps5169_redriver_write_reg_bits(ps5169, PS5169_DP_EQ0_REG, PS5169_DP_EQ0_VAL(eq), PS5169_DP_EQ0_MASK); ps5169_redriver_write_reg_bits(ps5169, PS5169_DP_EQ1_REG, PS5169_DP_EQ1_VAL(eq), PS5169_DP_EQ1_MASK); return 0; } static int ps5169_config_dp_gain(struct ps5169_redriver *ps5169, unsigned int gain) { if (gain > PS5169_DP_GAIN_MAX) { dev_err(&ps5169->client->dev, "error dp gain value %u\n", gain); return -EINVAL; } ps5169_redriver_write_reg_bits(ps5169, PS5169_DP_GAIN_REG, gain, PS5169_DP_GAIN_MASK); return 0; } static int ps5169_config_usb_tx_eq(struct ps5169_redriver *ps5169, unsigned int eq) { if (eq > PS5169_USB_TX_EQ_MAX) { dev_err(&ps5169->client->dev, "error usb tx eq value %u\n", eq); return -EINVAL; } ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_TX_EQ0_REG, PS5169_USB_TX_EQ0_VAL(eq), PS5169_USB_TX_EQ0_MASK); ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_TX_EQ1_REG, PS5169_USB_TX_EQ1_VAL(eq), PS5169_USB_TX_EQ1_MASK); ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_TX_EQ2_REG, PS5169_USB_TX_EQ2_VAL(eq), PS5169_USB_TX_EQ2_MASK); return 0; } static int ps5169_config_usb_tx_gain(struct ps5169_redriver *ps5169, unsigned int gain) { if (gain > PS5169_USB_TX_GAIN_MAX) { dev_err(&ps5169->client->dev, "error usb tx gain value %u\n", gain); return -EINVAL; } ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_TX_GAIN_REG, gain, PS5169_USB_TX_GAIN_MASK); return 0; } static int ps5169_config_usb_rx_eq(struct ps5169_redriver *ps5169, unsigned int eq) { if (eq > PS5169_USB_RX_EQ_MAX) { dev_err(&ps5169->client->dev, "error usb rx eq value %u\n", eq); return -EINVAL; } ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_RX_EQ0_REG, PS5169_USB_RX_EQ0_VAL(eq), PS5169_USB_RX_EQ0_MASK); ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_RX_EQ1_REG, PS5169_USB_RX_EQ1_VAL(eq), PS5169_USB_RX_EQ1_MASK); ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_RX_EQ2_REG, PS5169_USB_RX_EQ2_VAL(eq), PS5169_USB_RX_EQ2_MASK); ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_RX_EQ3_REG, PS5169_USB_RX_EQ3_VAL(eq), PS5169_USB_RX_EQ3_MASK); return 0; } static int ps5169_config_usb_rx_gain(struct ps5169_redriver *ps5169, unsigned int gain) { if (gain > PS5169_USB_RX_GAIN_MAX) { dev_err(&ps5169->client->dev, "error usb rx gain value %u\n", gain); return -EINVAL; } ps5169_redriver_write_reg_bits(ps5169, PS5169_USB_RX_GAIN_REG, gain, PS5169_USB_RX_GAIN_MASK); return 0; } /* save user configuration and dump for device tree */ static inline void update_config_reg(struct ps5169_redriver *ps5169, unsigned int reg, unsigned int val, unsigned int mask) { int i; for (i = 0; i < ps5169->config_seqs_cnt; i++) if (ps5169->config_seqs[i].reg == reg) { ps5169->config_seqs[i].def &= ~mask; ps5169->config_seqs[i].def |= (val & mask); break; } if (i == ps5169->config_seqs_cnt) pr_err("can't find reg %u in init regs\n", reg); } static int dp_eq_get(void *data, u64 *val) { struct ps5169_redriver *ps5169 = data; *val = ps5169->dpeq; return 0; } static int dp_eq_set(void *data, u64 val) { int ret; struct ps5169_redriver *ps5169 = data; ret = ps5169_config_dp_eq(ps5169, val); if (ret) return ret; ps5169->dpeq = val; update_config_reg(ps5169, PS5169_DP_EQ0_REG, PS5169_DP_EQ0_VAL(val), PS5169_DP_EQ0_MASK); update_config_reg(ps5169, PS5169_DP_EQ1_REG, PS5169_DP_EQ1_VAL(val), PS5169_DP_EQ1_MASK); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(dp_eq_ops, dp_eq_get, dp_eq_set, "%llu\n"); static int dp_gain_get(void *data, u64 *val) { struct ps5169_redriver *ps5169 = data; *val = ps5169->dpgain; return 0; } static int dp_gain_set(void *data, u64 val) { int ret; struct ps5169_redriver *ps5169 = data; ret = ps5169_config_dp_gain(ps5169, val); if (ret) return ret; ps5169->dpgain = val; update_config_reg(ps5169, PS5169_DP_GAIN_REG, val, PS5169_DP_GAIN_MASK); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(dp_gain_ops, dp_gain_get, dp_gain_set, "%llu\n"); static int usb_tx_eq_get(void *data, u64 *val) { struct ps5169_redriver *ps5169 = data; *val = ps5169->usbtxeq; return 0; } static int usb_tx_eq_set(void *data, u64 val) { int ret; struct ps5169_redriver *ps5169 = data; ret = ps5169_config_usb_tx_eq(ps5169, val); if (ret) return ret; ps5169->usbtxeq = val; update_config_reg(ps5169, PS5169_USB_TX_EQ0_REG, PS5169_USB_TX_EQ0_VAL(val), PS5169_USB_TX_EQ0_MASK); update_config_reg(ps5169, PS5169_USB_TX_EQ1_REG, PS5169_USB_TX_EQ1_VAL(val), PS5169_USB_TX_EQ1_MASK); update_config_reg(ps5169, PS5169_USB_TX_EQ2_REG, PS5169_USB_TX_EQ2_VAL(val), PS5169_USB_TX_EQ2_MASK); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(usb_tx_eq_ops, usb_tx_eq_get, usb_tx_eq_set, "%llu\n"); static int usb_tx_gain_get(void *data, u64 *val) { struct ps5169_redriver *ps5169 = data; *val = ps5169->usbtxgain; return 0; } static int usb_tx_gain_set(void *data, u64 val) { int ret; struct ps5169_redriver *ps5169 = data; ret = ps5169_config_usb_tx_gain(ps5169, val); if (ret) return ret; ps5169->usbtxgain = val; update_config_reg(ps5169, PS5169_USB_TX_GAIN_REG, val, PS5169_USB_TX_GAIN_MASK); return ret; } DEFINE_DEBUGFS_ATTRIBUTE(usb_tx_gain_ops, usb_tx_gain_get, usb_tx_gain_set, "%llu\n"); static int usb_rx_eq_get(void *data, u64 *val) { struct ps5169_redriver *ps5169 = data; *val = ps5169->usbrxeq; return 0; } static int usb_rx_eq_set(void *data, u64 val) { int ret; struct ps5169_redriver *ps5169 = data; ret = ps5169_config_usb_rx_eq(ps5169, val); if (ret) return ret; ps5169->usbtxeq = val; update_config_reg(ps5169, PS5169_USB_RX_EQ0_REG, PS5169_USB_RX_EQ0_VAL(val), PS5169_USB_RX_EQ0_MASK); update_config_reg(ps5169, PS5169_USB_RX_EQ1_REG, PS5169_USB_RX_EQ1_VAL(val), PS5169_USB_RX_EQ1_MASK); update_config_reg(ps5169, PS5169_USB_RX_EQ2_REG, PS5169_USB_RX_EQ2_VAL(val), PS5169_USB_RX_EQ2_MASK); update_config_reg(ps5169, PS5169_USB_RX_EQ3_REG, PS5169_USB_RX_EQ3_VAL(val), PS5169_USB_RX_EQ3_MASK); return 0; } DEFINE_DEBUGFS_ATTRIBUTE(usb_rx_eq_ops, usb_rx_eq_get, usb_rx_eq_set, "%llu\n"); static int usb_rx_gain_get(void *data, u64 *val) { struct ps5169_redriver *ps5169 = data; *val = ps5169->usbrxgain; return 0; } static int usb_rx_gain_set(void *data, u64 val) { int ret; struct ps5169_redriver *ps5169 = data; ret = ps5169_config_usb_rx_gain(ps5169, val); if (ret) return ret; ps5169->usbrxgain = val; update_config_reg(ps5169, PS5169_USB_RX_GAIN_REG, val, PS5169_USB_RX_GAIN_MASK); return ret; } static int config_seqs_show(struct seq_file *s, void *unused) { struct ps5169_redriver *ps5169 = s->private; int i; for (i = 0; i < ps5169->config_seqs_cnt; i++) seq_printf(s, "0x%02x 0x%02x %u\n", ps5169->config_seqs[i].reg, ps5169->config_seqs[i].def, ps5169->config_seqs[i].delay_us); return 0; } DEFINE_SHOW_ATTRIBUTE(config_seqs); DEFINE_DEBUGFS_ATTRIBUTE(usb_rx_gain_ops, usb_rx_gain_get, usb_rx_gain_set, "%llu\n"); static void ps5169_debugfs_create(struct ps5169_redriver *ps5169) { struct i2c_client *client = ps5169->client; ps5169->debug_root = debugfs_create_dir("ps5169", NULL); if (!ps5169->debug_root) { dev_warn(&client->dev, "couldn't create debug dir\n"); return; } debugfs_create_file("dp-eq", 0644, ps5169->debug_root, ps5169, &dp_eq_ops); debugfs_create_file("dp-gain", 0644, ps5169->debug_root, ps5169, &dp_gain_ops); debugfs_create_file("usb-tx-eq", 0644, ps5169->debug_root, ps5169, &usb_tx_eq_ops); debugfs_create_file("usb-tx-gain", 0644, ps5169->debug_root, ps5169, &usb_tx_gain_ops); debugfs_create_file("usb-rx-eq", 0644, ps5169->debug_root, ps5169, &usb_rx_eq_ops); debugfs_create_file("usb-rx-gain", 0644, ps5169->debug_root, ps5169, &usb_rx_gain_ops); debugfs_create_file("config_seqs", 0444, ps5169->debug_root, ps5169, &config_seqs_fops); } static int ps5169_config_seqs_init(struct ps5169_redriver *ps5169) { int ret = 0; regmap_register_patch(ps5169->regmap, ps5169->config_seqs, ps5169->config_seqs_cnt); ret = ps5169_redriver_write_reg_bits(ps5169, PS5169_CONFIG_REG, PS5169_PD_ACTIVE, PS5169_PD_ACTIVE); return ret; } static void ps5169_config_work_mode(struct ps5169_redriver *ps5169, enum operation_mode mode) { struct i2c_client *client = ps5169->client; unsigned int val, mask; switch (mode) { case OP_MODE_NONE: mask = PS5169_PD_ACTIVE | PS5169_USB3_EN | PS5169_DP_EN; val = PS5169_PD_ACTIVE; dev_dbg(&client->dev, "write config %02x | %02x\n", val, mask); ps5169_redriver_write_reg_bits(ps5169, PS5169_CONFIG_REG, val, mask); ps5169_redriver_write_reg_bits(ps5169, 0xa0, 0x02, 0xff); ps5169_redriver_write_reg_bits(ps5169, 0xa1, 0x00, 0xff); break; case OP_MODE_USB3: mask = PS5169_PD_ACTIVE | PS5169_USB3_EN | PS5169_DP_EN | PS5169_FLIPPED; val = PS5169_PD_ACTIVE | PS5169_USB3_EN; if (ps5169->typec_orientation == ORIENTATION_CC2) val |= PS5169_FLIPPED; dev_dbg(&client->dev, "write config %02x | %02x\n", val, mask); ps5169_redriver_write_reg_bits(ps5169, PS5169_CONFIG_REG, val, mask); break; case OP_MODE_DP: mask = PS5169_PD_ACTIVE | PS5169_USB3_EN | PS5169_DP_EN | PS5169_FLIPPED; val = PS5169_PD_ACTIVE | PS5169_DP_EN; if (ps5169->typec_orientation == ORIENTATION_CC2) val |= PS5169_FLIPPED; dev_dbg(&client->dev, "write config %02x | %02x\n", val, mask); ps5169_redriver_write_reg_bits(ps5169, PS5169_CONFIG_REG, val, mask); ps5169_redriver_write_reg_bits(ps5169, 0xa0, 0x00, 0xff); ps5169_redriver_write_reg_bits(ps5169, 0xa1, 0x04, 0xff); break; case OP_MODE_USB3_AND_DP: mask = PS5169_PD_ACTIVE | PS5169_USB3_EN | PS5169_DP_EN | PS5169_FLIPPED; val = PS5169_PD_ACTIVE | PS5169_USB3_EN | PS5169_DP_EN; if (ps5169->typec_orientation == ORIENTATION_CC2) val |= PS5169_FLIPPED; dev_dbg(&client->dev, "write config %02x | %02x\n", val, mask); ps5169_redriver_write_reg_bits(ps5169, PS5169_CONFIG_REG, val, mask); ps5169_redriver_write_reg_bits(ps5169, 0xa0, 0x00, 0xff); ps5169_redriver_write_reg_bits(ps5169, 0xa1, 0x04, 0xff); break; default: pr_err("operation mode is not support\n"); return; } } static const struct regmap_config ps5169_regmap = { .max_register = 0xff, .reg_bits = 8, .val_bits = 8, }; static int ps5169_i2c_probe(struct i2c_client *client, const struct i2c_device_id *dev_id) { struct device *dev = &client->dev; struct ps5169_redriver *ps5169; int ret, size = 0; u32 device_id; ps5169 = devm_kzalloc(dev, sizeof(*ps5169), GFP_KERNEL); if (!ps5169) return -ENOMEM; ps5169->dev = dev; ps5169->client = client; ps5169_redriver_gpio_init(ps5169); of_get_property(dev->of_node, "config-seq", &size); if (!size || size % (3 * sizeof(unsigned int))) { dev_err(dev, "no config-seq or size is wrong\n"); return -EINVAL; } ps5169->config_seqs = devm_kzalloc(dev, size, GFP_KERNEL); if (!ps5169->config_seqs) return -ENOMEM; ps5169->config_seqs_cnt = size / (3 * sizeof(unsigned int)); of_property_read_u32_array(dev->of_node, "config-seq", (u32 *)ps5169->config_seqs, ps5169->config_seqs_cnt * 3); ps5169->regmap = devm_regmap_init_i2c(client, &ps5169_regmap); if (IS_ERR(ps5169->regmap)) { ret = PTR_ERR(ps5169->regmap); dev_err(dev, "failed to allocate register map: %d\n", ret); return ret; } ps5169->vcc = devm_regulator_get_optional(&client->dev, "vcc"); if (IS_ERR(ps5169->vcc) || ps5169->vcc == NULL) { dev_err(&client->dev, "Could not get vcc power regulator\n"); } else { ret = regulator_enable(ps5169->vcc); if (ret) dev_err(&client->dev, "Could not enable vcc power regulator\n"); } ps5169->vio = devm_regulator_get_optional(&client->dev, "vio"); if (IS_ERR(ps5169->vio) || ps5169->vio == NULL) { dev_err(&client->dev, "Could not get vio power regulator\n"); } else { ret = regulator_enable(ps5169->vio); if (ret) dev_err(&client->dev, "Could not enable vio power regulator\n"); } ps5169_redriver_enable_chip(ps5169, true); ret = regmap_raw_read(ps5169->regmap, PS5169_CHIPID_REG, &device_id, 2); if (ret != 0) { dev_err(dev, "%s,device id read failed:%d\n", __func__, ret); } else if (device_id != PS5169_CHIP_ID) { dev_err(dev, "%s,device id unknown: 0x%x\n", __func__, device_id); } dev_info(dev, "%s,device_id=0x%x\n", __func__, device_id); i2c_set_clientdata(client, ps5169); ps5169_config_seqs_init(ps5169); /* how about USB enumerated before this driver load */ ps5169_config_work_mode(ps5169, OP_MODE_NONE); ps5169->op_mode = OP_MODE_NONE; ps5169_redriver_enable_chip(ps5169, false); ps5169_debugfs_create(ps5169); INIT_WORK(&ps5169->pullup_work, ps5169_gadget_pullup_work); INIT_WORK(&ps5169->host_work, ps5169_host_work); ps5169->r.of_node = ps5169->dev->of_node; ps5169->r.release_usb_lanes = ps5169_release_usb_lanes; ps5169->r.notify_connect = ps5169_notify_connect; ps5169->r.notify_disconnect = ps5169_notify_disconnect; ps5169->r.get_orientation = ps5169_get_orientation; ps5169->r.gadget_pullup_enter = ps5169_gadget_pullup_enter; ps5169->r.gadget_pullup_exit = ps5169_gadget_pullup_exit; ps5169->r.host_powercycle = ps5169_host_powercycle; usb_add_redriver(&ps5169->r); dev_info(dev, "%s,ps5169 probe done.\n", __func__); return 0; } static int ps5169_i2c_remove(struct i2c_client *client) { struct ps5169_redriver *ps5169 = i2c_get_clientdata(client); if (usb_remove_redriver(&ps5169->r)) return -EINVAL; debugfs_remove(ps5169->debug_root); if (!IS_ERR_OR_NULL(ps5169->vcc)) { if (regulator_is_enabled(ps5169->vcc)) regulator_disable(ps5169->vcc); devm_regulator_put(ps5169->vcc); } if (!IS_ERR_OR_NULL(ps5169->vio)) { if (regulator_is_enabled(ps5169->vio)) regulator_disable(ps5169->vio); devm_regulator_put(ps5169->vio); } if (gpio_is_valid(ps5169->enable_gpio)) { devm_gpio_free(ps5169->dev, ps5169->enable_gpio); ps5169->enable_gpio = -EINVAL; } if (gpio_is_valid(ps5169->orientation_gpio)) { devm_gpio_free(ps5169->dev, ps5169->orientation_gpio); ps5169->orientation_gpio = -EINVAL; } return 0; } static int __maybe_unused redriver_i2c_suspend(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct ps5169_redriver *ps5169 = i2c_get_clientdata(client); dev_dbg(ps5169->dev, "%s: SS USB redriver suspend.\n", __func__); /* * 1. when in 4 lanes display mode, it can't disable; * 2. when in NONE mode, there is no need to re-disable; * 3. when in DEFAULT mode, there is no adsp and can't disable; */ if (ps5169->op_mode == OP_MODE_DP || ps5169->op_mode == OP_MODE_NONE || ps5169->op_mode == OP_MODE_DEFAULT) return 0; ps5169_redriver_enable_chip(ps5169, false); return 0; } static int __maybe_unused redriver_i2c_resume(struct device *dev) { struct i2c_client *client = to_i2c_client(dev); struct ps5169_redriver *ps5169 = i2c_get_clientdata(client); dev_dbg(ps5169->dev, "%s: SS USB redriver resume.\n", __func__); /* no suspend happen in following mode */ if (ps5169->op_mode == OP_MODE_DP || ps5169->op_mode == OP_MODE_NONE || ps5169->op_mode == OP_MODE_DEFAULT) return 0; ps5169_redriver_enable_chip(ps5169, true); ps5169_config_seqs_init(ps5169); ps5169_config_work_mode(ps5169, ps5169->op_mode); return 0; } static SIMPLE_DEV_PM_OPS(redriver_i2c_pm, redriver_i2c_suspend, redriver_i2c_resume); static void ps5169_i2c_shutdown(struct i2c_client *client) { struct ps5169_redriver *ps5169 = i2c_get_clientdata(client); int ret; ret = ps5169_redriver_enable_chip(ps5169, false); if (ret < 0) dev_err(&client->dev, "%s: fail to disable redriver.\n", __func__); else dev_dbg(&client->dev, "%s: successfully disable redriver.\n", __func__); } static const struct of_device_id ps5169_match_table[] = { { .compatible = "parade,ps5169-redriver",}, { }, }; static const struct i2c_device_id ps5169_i2c_id[] = { { "ps5169 redriver", 0 }, { }, }; MODULE_DEVICE_TABLE(i2c, ps5169_i2c_id); static struct i2c_driver ps5169_i2c_driver = { .driver = { .name = "ps5169 redriver", .of_match_table = ps5169_match_table, .pm = &redriver_i2c_pm, }, .probe = ps5169_i2c_probe, .remove = ps5169_i2c_remove, .shutdown = ps5169_i2c_shutdown, .id_table = ps5169_i2c_id, }; module_i2c_driver(ps5169_i2c_driver); MODULE_DESCRIPTION("Parade PS5169 USB3.1 Gen2 Type-C 10Gbps Linear Redriver"); MODULE_LICENSE("GPL v2");