diff options
| author | Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com> | 2026-07-29 15:34:25 +0200 |
|---|---|---|
| committer | Bjorn Helgaas <bhelgaas@google.com> | 2026-08-31 12:29:20 -0500 |
| commit | ebaa06fc5bbeea062e6dc7b2f28f7b042f9cc2ca (patch) | |
| tree | 6bf9f3702fb6c62d8f13789b35b2cefcce2bdd95 /drivers | |
| parent | cee9395acd8043be0644b25c34bfa86623f2b935 (diff) | |
| download | linux-next-ebaa06fc5bbeea062e6dc7b2f28f7b042f9cc2ca.tar.gz linux-next-ebaa06fc5bbeea062e6dc7b2f28f7b042f9cc2ca.zip | |
PCI/pwrctrl: tc9563: Rely on regmap APIs
Replace the custom tc9563_pwrctrl_i2c_{read,write,bulk_write} functions
with standard regmap APIs. The device uses 24-bit big-endian register
addresses and 32-bit little-endian register values over I2C, which is
directly supported by regmap.
This removes the open-coded I2C transfer handling and lets the regmap
core handle formatting, locking, and multi-register coalescing.
Signed-off-by: Lorenzo Bianconi <lorenzo.bianconi@oss.qualcomm.com>
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Reviewed-by: Manivannan Sadhasivam <mani@kernel.org>
Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
Link: https://patch.msgid.link/20260729-pci-pwrctrl-tc956x-regmap-v1-1-20ce61a3ce12@oss.qualcomm.com
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/pci/pwrctrl/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c | 153 |
2 files changed, 44 insertions, 110 deletions
diff --git a/drivers/pci/pwrctrl/Kconfig b/drivers/pci/pwrctrl/Kconfig index 9eec767cda86..1952ab4f29b6 100644 --- a/drivers/pci/pwrctrl/Kconfig +++ b/drivers/pci/pwrctrl/Kconfig @@ -29,6 +29,7 @@ config PCI_PWRCTRL_TC9563 select PCI_PWRCTRL default m if ARCH_QCOM depends on I2C + select REGMAP_I2C help Say Y here to enable the PCI Power Control driver of TC9563 PCIe switch. diff --git a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c index fd53a7db9875..d2a0c4f8c03e 100644 --- a/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c +++ b/drivers/pci/pwrctrl/pci-pwrctrl-tc9563.c @@ -16,10 +16,10 @@ #include <linux/pci.h> #include <linux/pci-pwrctrl.h> #include <linux/platform_device.h> +#include <linux/regmap.h> #include <linux/regulator/consumer.h> #include <linux/string.h> #include <linux/types.h> -#include <linux/unaligned.h> #include "../pci.h" @@ -70,11 +70,6 @@ #define TC9563_L0S_L1_DELAY_UNIT_NS 256 /* Each unit represents 256 ns */ -struct tc9563_pwrctrl_reg_setting { - unsigned int offset; - unsigned int val; -}; - enum tc9563_pwrctrl_ports { TC9563_USP, TC9563_DSP1, @@ -111,13 +106,14 @@ struct tc9563_pwrctrl { struct gpio_desc *reset_gpio; struct i2c_adapter *adapter; struct i2c_client *client; + struct regmap *regmap; }; /* * downstream port power off sequence, hardcoding the address * as we don't know register names for these register offsets. */ -static const struct tc9563_pwrctrl_reg_setting common_pwroff_seq[] = { +static const struct reg_sequence common_pwroff_seq[] = { {0x82900c, 0x1}, {0x829010, 0x1}, {0x829018, 0x0}, @@ -140,7 +136,7 @@ static const struct tc9563_pwrctrl_reg_setting common_pwroff_seq[] = { {0x829114, 0x1}, }; -static const struct tc9563_pwrctrl_reg_setting dsp1_pwroff_seq[] = { +static const struct reg_sequence dsp1_pwroff_seq[] = { {TC9563_PORT_ACCESS_ENABLE, 0x2}, {TC9563_PORT_LANE_ACCESS_ENABLE, 0x3}, {TC9563_POWER_CONTROL, 0x014f4804}, @@ -148,7 +144,7 @@ static const struct tc9563_pwrctrl_reg_setting dsp1_pwroff_seq[] = { {TC9563_PORT_ACCESS_ENABLE, 0x4}, }; -static const struct tc9563_pwrctrl_reg_setting dsp2_pwroff_seq[] = { +static const struct reg_sequence dsp2_pwroff_seq[] = { {TC9563_PORT_ACCESS_ENABLE, 0x8}, {TC9563_PORT_LANE_ACCESS_ENABLE, 0x1}, {TC9563_POWER_CONTROL, 0x014f4804}, @@ -156,85 +152,11 @@ static const struct tc9563_pwrctrl_reg_setting dsp2_pwroff_seq[] = { {TC9563_PORT_ACCESS_ENABLE, 0x8}, }; -/* - * Since all transfers are initiated by the probe, no locks are necessary, - * as there are no concurrent calls. - */ -static int tc9563_pwrctrl_i2c_write(struct i2c_client *client, - u32 reg_addr, u32 reg_val) -{ - struct i2c_msg msg; - u8 msg_buf[7]; - int ret; - - msg.addr = client->addr; - msg.len = 7; - msg.flags = 0; - - /* Big Endian for reg addr */ - put_unaligned_be24(reg_addr, &msg_buf[0]); - - /* Little Endian for reg val */ - put_unaligned_le32(reg_val, &msg_buf[3]); - - msg.buf = msg_buf; - ret = i2c_transfer(client->adapter, &msg, 1); - return ret == 1 ? 0 : ret; -} - -static int tc9563_pwrctrl_i2c_read(struct i2c_client *client, - u32 reg_addr, u32 *reg_val) -{ - struct i2c_msg msg[2]; - u8 wr_data[3]; - u32 rd_data; - int ret; - - msg[0].addr = client->addr; - msg[0].len = 3; - msg[0].flags = 0; - - /* Big Endian for reg addr */ - put_unaligned_be24(reg_addr, &wr_data[0]); - - msg[0].buf = wr_data; - - msg[1].addr = client->addr; - msg[1].len = 4; - msg[1].flags = I2C_M_RD; - - msg[1].buf = (u8 *)&rd_data; - - ret = i2c_transfer(client->adapter, &msg[0], 2); - if (ret == 2) { - *reg_val = get_unaligned_le32(&rd_data); - return 0; - } - - /* If only one message successfully completed, return -EIO */ - return ret == 1 ? -EIO : ret; -} - -static int tc9563_pwrctrl_i2c_bulk_write(struct i2c_client *client, - const struct tc9563_pwrctrl_reg_setting *seq, - int len) -{ - int ret, i; - - for (i = 0; i < len; i++) { - ret = tc9563_pwrctrl_i2c_write(client, seq[i].offset, seq[i].val); - if (ret) - return ret; - } - - return 0; -} - static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl *tc9563, enum tc9563_pwrctrl_ports port) { struct tc9563_pwrctrl_cfg *cfg = &tc9563->cfg[port]; - const struct tc9563_pwrctrl_reg_setting *seq; + const struct reg_sequence *seq; int ret, len; if (!cfg->disable_port) @@ -254,12 +176,12 @@ static int tc9563_pwrctrl_disable_port(struct tc9563_pwrctrl *tc9563, return 0; } - ret = tc9563_pwrctrl_i2c_bulk_write(tc9563->client, seq, len); + ret = regmap_multi_reg_write(tc9563->regmap, seq, len); if (ret) return ret; - return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, common_pwroff_seq, - ARRAY_SIZE(common_pwroff_seq)); + return regmap_multi_reg_write(tc9563->regmap, common_pwroff_seq, + ARRAY_SIZE(common_pwroff_seq)); } static int tc9563_pwrctrl_set_port_l0s_l1_entry_delay(struct tc9563_pwrctrl *tc9563, @@ -275,14 +197,13 @@ static int tc9563_pwrctrl_set_port_l0s_l1_entry_delay(struct tc9563_pwrctrl *tc9 /* convert to units of 256ns */ units = ns / TC9563_L0S_L1_DELAY_UNIT_NS; - ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_PORT_SELECT, - BIT(port)); + ret = regmap_write(tc9563->regmap, TC9563_PORT_SELECT, BIT(port)); if (ret) return ret; - return tc9563_pwrctrl_i2c_write(tc9563->client, - is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, - units); + return regmap_write(tc9563->regmap, + is_l1 ? TC9563_PORT_L1_DELAY : TC9563_PORT_L0S_DELAY, + units); } static int tc9563_pwrctrl_set_eth_l0s_l1_entry_delay(struct tc9563_pwrctrl *tc9563, @@ -297,8 +218,7 @@ static int tc9563_pwrctrl_set_eth_l0s_l1_entry_delay(struct tc9563_pwrctrl *tc95 /* convert to units of 256ns */ units = ns / TC9563_L0S_L1_DELAY_UNIT_NS; - ret = tc9563_pwrctrl_i2c_read(tc9563->client, TC9563_EMBEDDED_ETH_DELAY, - &rd_val); + ret = regmap_read(tc9563->regmap, TC9563_EMBEDDED_ETH_DELAY, &rd_val); if (ret) return ret; @@ -309,8 +229,7 @@ static int tc9563_pwrctrl_set_eth_l0s_l1_entry_delay(struct tc9563_pwrctrl *tc95 rd_val = u32_replace_bits(rd_val, units, TC9563_ETH_L0S_DELAY_MASK); - return tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_EMBEDDED_ETH_DELAY, - rd_val); + return regmap_write(tc9563->regmap, TC9563_EMBEDDED_ETH_DELAY, rd_val); } static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl *tc9563, @@ -343,14 +262,14 @@ static int tc9563_pwrctrl_set_tx_amplitude(struct tc9563_pwrctrl *tc9563, return -EINVAL; } - struct tc9563_pwrctrl_reg_setting tx_amp_seq[] = { + struct reg_sequence tx_amp_seq[] = { {TC9563_PORT_ACCESS_ENABLE, port_access}, {TC9563_PORT_LANE_ACCESS_ENABLE, 0x3}, {TC9563_TX_MARGIN, amp}, }; - return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, tx_amp_seq, - ARRAY_SIZE(tx_amp_seq)); + return regmap_multi_reg_write(tc9563->regmap, tx_amp_seq, + ARRAY_SIZE(tx_amp_seq)); } static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl *tc9563, @@ -383,7 +302,7 @@ static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl *tc9563, return -EINVAL; } - struct tc9563_pwrctrl_reg_setting disable_dfe_seq[] = { + struct reg_sequence disable_dfe_seq[] = { {TC9563_PORT_ACCESS_ENABLE, port_access}, {TC9563_PORT_LANE_ACCESS_ENABLE, lane_access}, {TC9563_DFE_ENABLE, 0x0}, @@ -397,15 +316,15 @@ static int tc9563_pwrctrl_disable_dfe(struct tc9563_pwrctrl *tc9563, {TC9563_PHY_RATE_CHANGE_OVERRIDE, 0x0}, }; - return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, disable_dfe_seq, - ARRAY_SIZE(disable_dfe_seq)); + return regmap_multi_reg_write(tc9563->regmap, disable_dfe_seq, + ARRAY_SIZE(disable_dfe_seq)); } static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl *tc9563, enum tc9563_pwrctrl_ports port) { u8 *nfts = tc9563->cfg[port].nfts; - struct tc9563_pwrctrl_reg_setting nfts_seq[] = { + struct reg_sequence nfts_seq[] = { {TC9563_NFTS_2_5_GT, nfts[0]}, {TC9563_NFTS_5_GT, nfts[1]}, }; @@ -420,13 +339,12 @@ static int tc9563_pwrctrl_set_nfts(struct tc9563_pwrctrl *tc9563, return 0; } - ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_PORT_SELECT, - BIT(port)); + ret = regmap_write(tc9563->regmap, TC9563_PORT_SELECT, BIT(port)); if (ret) return ret; - return tc9563_pwrctrl_i2c_bulk_write(tc9563->client, nfts_seq, - ARRAY_SIZE(nfts_seq)); + return regmap_multi_reg_write(tc9563->regmap, nfts_seq, + ARRAY_SIZE(nfts_seq)); } static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl *tc9563, @@ -434,14 +352,14 @@ static int tc9563_pwrctrl_assert_deassert_reset(struct tc9563_pwrctrl *tc9563, { int ret, val; - ret = tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_GPIO_CONFIG, - TC9563_GPIO_MASK); + ret = regmap_write(tc9563->regmap, TC9563_GPIO_CONFIG, + TC9563_GPIO_MASK); if (ret) return ret; val = deassert ? TC9563_GPIO_DEASSERT_BITS : 0; - return tc9563_pwrctrl_i2c_write(tc9563->client, TC9563_RESET_GPIO, val); + return regmap_write(tc9563->regmap, TC9563_RESET_GPIO, val); } static int tc9563_pwrctrl_parse_device_dt(struct device_node *node, @@ -572,6 +490,13 @@ power_off: return ret; } +static const struct regmap_config tc9563_regmap_config = { + .reg_bits = 24, + .val_bits = 32, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_LITTLE, +}; + static int tc9563_pwrctrl_probe(struct platform_device *pdev) { struct device_node *node = pdev->dev.of_node; @@ -602,6 +527,14 @@ static int tc9563_pwrctrl_probe(struct platform_device *pdev) return PTR_ERR(tc9563->client); } + tc9563->regmap = devm_regmap_init_i2c(tc9563->client, + &tc9563_regmap_config); + if (IS_ERR(tc9563->regmap)) { + ret = dev_err_probe(dev, PTR_ERR(tc9563->regmap), + "Failed to allocate register map\n"); + goto remove_i2c; + } + for (int i = 0; i < ARRAY_SIZE(tc9563_supply_names); i++) tc9563->supplies[i].supply = tc9563_supply_names[i]; |
