Message ID | 20240830-nxp-ptn3222-v2-2-4c6d8535cf6c@linaro.org (mailing list archive) |
---|---|
State | Not Applicable |
Headers | show |
Series | phy: add NXP PTN3222 eUSB2 to USB2 redriver | expand |
On 8/30/2024 4:20 PM, Dmitry Baryshkov wrote: > The NXP PTN3222 is the single-port eUSB2 to USB2 redriver that performs > translation between eUSB2 and USB2 signalling schemes. It supports all > three data rates: Low Speed, Full Speed and High Speed. > > The reset state enables autonegotiation of the PHY role and of the data > rate, so no additional programming is required. > > Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> > Tested-by: Konrad Dybcio <konradybcio@kernel.org> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> > --- > drivers/phy/Kconfig | 11 ++++ > drivers/phy/Makefile | 1 + > drivers/phy/phy-nxp-ptn3222.c | 123 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 135 insertions(+) > > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig > index dfab1c66b3e5..cb06a7f79740 100644 > --- a/drivers/phy/Kconfig > +++ b/drivers/phy/Kconfig > @@ -82,6 +82,17 @@ config PHY_AIROHA_PCIE > This driver create the basic PHY instance and provides initialize > callback for PCIe GEN3 port. > > +config PHY_NXP_PTN3222 > + tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver" > + depends on I2C > + depends on OF > + select GENERIC_PHY > + help > + Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver. > + This redriver performs translation between eUSB2 and USB2 signalling > + schemes. It supports all three USB 2.0 data rates: Low Speed, Full > + Speed and High Speed. > + > source "drivers/phy/allwinner/Kconfig" > source "drivers/phy/amlogic/Kconfig" > source "drivers/phy/broadcom/Kconfig" > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile > index 5fcbce5f9ab1..b64247046575 100644 > --- a/drivers/phy/Makefile > +++ b/drivers/phy/Makefile > @@ -11,6 +11,7 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o > obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o > obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o > obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o > +obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o > obj-y += allwinner/ \ > amlogic/ \ > broadcom/ \ > diff --git a/drivers/phy/phy-nxp-ptn3222.c b/drivers/phy/phy-nxp-ptn3222.c > new file mode 100644 > index 000000000000..c6179d8701e6 > --- /dev/null > +++ b/drivers/phy/phy-nxp-ptn3222.c > @@ -0,0 +1,123 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2024, Linaro Limited > + */ > + > +#include <linux/gpio/consumer.h> > +#include <linux/i2c.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/phy/phy.h> > +#include <linux/regmap.h> > +#include <linux/regulator/consumer.h> > + > +#define NUM_SUPPLIES 2 > + > +struct ptn3222 { > + struct i2c_client *client; > + struct phy *phy; > + struct gpio_desc *reset_gpio; > + struct regulator_bulk_data *supplies; > +}; > + > +static int ptn3222_init(struct phy *phy) > +{ > + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); > + int ret; > + > + ret = regulator_bulk_enable(NUM_SUPPLIES, ptn3222->supplies); > + if (ret) > + return ret; > + > + gpiod_set_value_cansleep(ptn3222->reset_gpio, 0); > + > + return 0; > +} > + > +static int ptn3222_exit(struct phy *phy) > +{ > + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); > + > + gpiod_set_value_cansleep(ptn3222->reset_gpio, 1); > + > + return regulator_bulk_disable(NUM_SUPPLIES, ptn3222->supplies); > +} > + > +static const struct phy_ops ptn3222_ops = { > + .init = ptn3222_init, > + .exit = ptn3222_exit, > + .owner = THIS_MODULE, > +}; > + > +static const struct regulator_bulk_data ptn3222_supplies[NUM_SUPPLIES] = { > + { > + .supply = "vdd3v3", > + .init_load_uA = 11000, > + }, { > + .supply = "vdd1v8", > + .init_load_uA = 55000, > + } > +}; > + > +static int ptn3222_probe(struct i2c_client *client) > +{ > + struct device *dev = &client->dev; > + struct phy_provider *phy_provider; > + struct ptn3222 *ptn3222; > + int ret; > + > + ptn3222 = devm_kzalloc(dev, sizeof(*ptn3222), GFP_KERNEL); > + if (!ptn3222) > + return -ENOMEM; > + > + ptn3222->client = client; > + > + ptn3222->reset_gpio = devm_gpiod_get_optional(dev, "reset", > + GPIOD_OUT_HIGH); > + if (IS_ERR(ptn3222->reset_gpio)) > + return dev_err_probe(dev, PTR_ERR(ptn3222->reset_gpio), > + "unable to acquire reset gpio\n"); > + > + ret = devm_regulator_bulk_get_const(dev, NUM_SUPPLIES, ptn3222_supplies, > + &ptn3222->supplies); > + if (ret) > + return ret; > + > + ptn3222->phy = devm_phy_create(dev, dev->of_node, &ptn3222_ops); > + if (IS_ERR(ptn3222->phy)) { > + dev_err(dev, "failed to create PHY: %d\n", ret); > + return PTR_ERR(ptn3222->phy); > + } > + > + phy_set_drvdata(ptn3222->phy, ptn3222); > + > + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > + > + return PTR_ERR_OR_ZERO(phy_provider); > +} > + > +static const struct i2c_device_id ptn3222_table[] = { > + { "ptn3222" }, > + { } > +}; > +MODULE_DEVICE_TABLE(i2c, ptn3222_table); > + > +static const struct of_device_id ptn3222_of_table[] = { > + { .compatible = "nxp,ptn3222" }, > + { } > +}; > +MODULE_DEVICE_TABLE(of, ptn3222_of_table); > + > +static struct i2c_driver ptn3222_driver = { > + .driver = { > + .name = "ptn3222", > + .of_match_table = ptn3222_of_table, > + }, > + .probe = ptn3222_probe, > + .id_table = ptn3222_table, > +}; > + > +module_i2c_driver(ptn3222_driver) > + > +MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); > +MODULE_LICENSE("GPL"); > The I2C driver just realizes the function on reset and PWR. What about other I2C driver function like I2C interface operations, auto-suspend, remote wakeup, memory maps etc. Who will enable these? I think it is not incomplete I2C driver, if on someday, ptn3222 is used as I2C device. Regards, Song Xue
On Sat, 31 Aug 2024 at 02:13, Song Xue <quic_songxue@quicinc.com> wrote: > On 8/30/2024 4:20 PM, Dmitry Baryshkov wrote: > > The NXP PTN3222 is the single-port eUSB2 to USB2 redriver that performs > > translation between eUSB2 and USB2 signalling schemes. It supports all > > three data rates: Low Speed, Full Speed and High Speed. > > > > The reset state enables autonegotiation of the PHY role and of the data > > rate, so no additional programming is required. > > > > Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> > > Tested-by: Konrad Dybcio <konradybcio@kernel.org> > > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> > > --- > > drivers/phy/Kconfig | 11 ++++ > > drivers/phy/Makefile | 1 + > > drivers/phy/phy-nxp-ptn3222.c | 123 ++++++++++++++++++++++++++++++++++++++++++ > > 3 files changed, 135 insertions(+) [trimmed] > > + > > +MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); > > +MODULE_LICENSE("GPL"); > > > The I2C driver just realizes the function on reset and PWR. What about > other I2C driver function like I2C interface operations, I don't quite understand what you mean by this. Could you please clarify? > auto-suspend, I think you mean pm_runtime here. It's a valid case, but granted that it should stay enabled when USB controller is enabled, the gain should be pretty limited. I'll consider a followup patch implementing pm_runtime for the sake of being able to disable I2C host if DWC3 controller disables the PHY. > remote wakeup, Not supported by design. PTN3222 doesn't have IRQ pins to report events to the host. > memory maps etc. huh? > Who will enable these? I think it is not > incomplete I2C driver, if on someday, ptn3222 is used as I2C device. Well, I'm using it as an I2C device.
On 8/31/2024 7:45 AM, Dmitry Baryshkov wrote: > On Sat, 31 Aug 2024 at 02:13, Song Xue <quic_songxue@quicinc.com> wrote: >> On 8/30/2024 4:20 PM, Dmitry Baryshkov wrote: >>> The NXP PTN3222 is the single-port eUSB2 to USB2 redriver that performs >>> translation between eUSB2 and USB2 signalling schemes. It supports all >>> three data rates: Low Speed, Full Speed and High Speed. >>> >>> The reset state enables autonegotiation of the PHY role and of the data >>> rate, so no additional programming is required. >>> >>> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> >>> Tested-by: Konrad Dybcio <konradybcio@kernel.org> >>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> >>> --- >>> drivers/phy/Kconfig | 11 ++++ >>> drivers/phy/Makefile | 1 + >>> drivers/phy/phy-nxp-ptn3222.c | 123 ++++++++++++++++++++++++++++++++++++++++++ >>> 3 files changed, 135 insertions(+) > > [trimmed] > >>> + >>> +MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); >>> +MODULE_LICENSE("GPL"); >>> >> The I2C driver just realizes the function on reset and PWR. What about >> other I2C driver function like I2C interface operations, > > I don't quite understand what you mean by this. Could you please clarify? > >> auto-suspend, > > I think you mean pm_runtime here. It's a valid case, but granted that > it should stay enabled when USB controller is enabled, the gain should > be pretty limited. I'll consider a followup patch implementing > pm_runtime for the sake of being able to disable I2C host if DWC3 > controller disables the PHY. > >> remote wakeup, > > Not supported by design. PTN3222 doesn't have IRQ pins to report > events to the host. > >> memory maps etc. > > huh? > >> Who will enable these? I think it is not >> incomplete I2C driver, if on someday, ptn3222 is used as I2C device. > > Well, I'm using it as an I2C device. > Sorry for the delayed response. The functions I listed, such as auto-suspend and wake-up, are just examples. My main point is that a basic I2C driver should include fundamental functions like setting up the I2C bus, configuring the clock, and setting the SDA (data line) and SCL (clock line). A basic I2C driver shouldn’t be limited to enabling the power supply and reset pin, as these features can be handled by other drivers as well. If you implement these fundamental functions, I think it will be sufficient. Regards, Song Xue
On Fri, 6 Sept 2024 at 11:40, Song Xue <quic_songxue@quicinc.com> wrote: > > > > On 8/31/2024 7:45 AM, Dmitry Baryshkov wrote: > > On Sat, 31 Aug 2024 at 02:13, Song Xue <quic_songxue@quicinc.com> wrote: > >> On 8/30/2024 4:20 PM, Dmitry Baryshkov wrote: > >>> The NXP PTN3222 is the single-port eUSB2 to USB2 redriver that performs > >>> translation between eUSB2 and USB2 signalling schemes. It supports all > >>> three data rates: Low Speed, Full Speed and High Speed. > >>> > >>> The reset state enables autonegotiation of the PHY role and of the data > >>> rate, so no additional programming is required. > >>> > >>> Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> > >>> Tested-by: Konrad Dybcio <konradybcio@kernel.org> > >>> Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> > >>> --- > >>> drivers/phy/Kconfig | 11 ++++ > >>> drivers/phy/Makefile | 1 + > >>> drivers/phy/phy-nxp-ptn3222.c | 123 ++++++++++++++++++++++++++++++++++++++++++ > >>> 3 files changed, 135 insertions(+) > > > > [trimmed] > > > >>> + > >>> +MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); > >>> +MODULE_LICENSE("GPL"); > >>> > >> The I2C driver just realizes the function on reset and PWR. What about > >> other I2C driver function like I2C interface operations, > > > > I don't quite understand what you mean by this. Could you please clarify? > > > >> auto-suspend, > > > > I think you mean pm_runtime here. It's a valid case, but granted that > > it should stay enabled when USB controller is enabled, the gain should > > be pretty limited. I'll consider a followup patch implementing > > pm_runtime for the sake of being able to disable I2C host if DWC3 > > controller disables the PHY. > > > >> remote wakeup, > > > > Not supported by design. PTN3222 doesn't have IRQ pins to report > > events to the host. > > > >> memory maps etc. > > > > huh? > > > >> Who will enable these? I think it is not > >> incomplete I2C driver, if on someday, ptn3222 is used as I2C device. > > > > Well, I'm using it as an I2C device. > > > Sorry for the delayed response. > The functions I listed, such as auto-suspend and wake-up, are just > examples. My main point is that a basic I2C driver should include > fundamental functions like setting up the I2C bus, configuring the > clock, and setting the SDA (data line) and SCL (clock line). A basic I2C > driver shouldn’t be limited to enabling the power supply and reset pin, > as these features can be handled by other drivers as well. > If you implement these fundamental functions, I think it will be sufficient. I think you have mixed two things. You are describing an I2C bus device, which PTN3222 isn't. I2C clients do not have to setup anything. SDA/SCL and clock frequency are handled by the I2C bus drivers and by the I2C framework.
On Fri, Aug 30, 2024 at 11:20:46AM +0300, Dmitry Baryshkov wrote: > The NXP PTN3222 is the single-port eUSB2 to USB2 redriver that performs > translation between eUSB2 and USB2 signalling schemes. It supports all > three data rates: Low Speed, Full Speed and High Speed. > > The reset state enables autonegotiation of the PHY role and of the data > rate, so no additional programming is required. > > Reviewed-by: Neil Armstrong <neil.armstrong@linaro.org> > Tested-by: Konrad Dybcio <konradybcio@kernel.org> > Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org> This works well for the USB fingerprint reader on the Qualcomm X1E80100 CRD. Thanks a lot for the clean driver :-) Reviewed-by: Stephan Gerhold <stephan.gerhold@linaro.org> Tested-by: Stephan Gerhold <stephan.gerhold@linaro.org> > --- > drivers/phy/Kconfig | 11 ++++ > drivers/phy/Makefile | 1 + > drivers/phy/phy-nxp-ptn3222.c | 123 ++++++++++++++++++++++++++++++++++++++++++ > 3 files changed, 135 insertions(+) > > diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig > index dfab1c66b3e5..cb06a7f79740 100644 > --- a/drivers/phy/Kconfig > +++ b/drivers/phy/Kconfig > @@ -82,6 +82,17 @@ config PHY_AIROHA_PCIE > This driver create the basic PHY instance and provides initialize > callback for PCIe GEN3 port. > > +config PHY_NXP_PTN3222 > + tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver" > + depends on I2C > + depends on OF > + select GENERIC_PHY > + help > + Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver. > + This redriver performs translation between eUSB2 and USB2 signalling > + schemes. It supports all three USB 2.0 data rates: Low Speed, Full > + Speed and High Speed. > + > source "drivers/phy/allwinner/Kconfig" > source "drivers/phy/amlogic/Kconfig" > source "drivers/phy/broadcom/Kconfig" > diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile > index 5fcbce5f9ab1..b64247046575 100644 > --- a/drivers/phy/Makefile > +++ b/drivers/phy/Makefile > @@ -11,6 +11,7 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o > obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o > obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o > obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o > +obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o > obj-y += allwinner/ \ > amlogic/ \ > broadcom/ \ > diff --git a/drivers/phy/phy-nxp-ptn3222.c b/drivers/phy/phy-nxp-ptn3222.c > new file mode 100644 > index 000000000000..c6179d8701e6 > --- /dev/null > +++ b/drivers/phy/phy-nxp-ptn3222.c > @@ -0,0 +1,123 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Copyright (c) 2024, Linaro Limited > + */ > + > +#include <linux/gpio/consumer.h> > +#include <linux/i2c.h> > +#include <linux/module.h> > +#include <linux/of.h> > +#include <linux/phy/phy.h> > +#include <linux/regmap.h> > +#include <linux/regulator/consumer.h> > + > +#define NUM_SUPPLIES 2 > + > +struct ptn3222 { > + struct i2c_client *client; > + struct phy *phy; > + struct gpio_desc *reset_gpio; > + struct regulator_bulk_data *supplies; > +}; > + > +static int ptn3222_init(struct phy *phy) > +{ > + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); > + int ret; > + > + ret = regulator_bulk_enable(NUM_SUPPLIES, ptn3222->supplies); > + if (ret) > + return ret; > + > + gpiod_set_value_cansleep(ptn3222->reset_gpio, 0); > + > + return 0; > +} > + > +static int ptn3222_exit(struct phy *phy) > +{ > + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); > + > + gpiod_set_value_cansleep(ptn3222->reset_gpio, 1); > + > + return regulator_bulk_disable(NUM_SUPPLIES, ptn3222->supplies); > +} > + > +static const struct phy_ops ptn3222_ops = { > + .init = ptn3222_init, > + .exit = ptn3222_exit, > + .owner = THIS_MODULE, > +}; > + > +static const struct regulator_bulk_data ptn3222_supplies[NUM_SUPPLIES] = { > + { > + .supply = "vdd3v3", > + .init_load_uA = 11000, > + }, { > + .supply = "vdd1v8", > + .init_load_uA = 55000, > + } > +}; > + > +static int ptn3222_probe(struct i2c_client *client) > +{ > + struct device *dev = &client->dev; > + struct phy_provider *phy_provider; > + struct ptn3222 *ptn3222; > + int ret; > + > + ptn3222 = devm_kzalloc(dev, sizeof(*ptn3222), GFP_KERNEL); > + if (!ptn3222) > + return -ENOMEM; > + > + ptn3222->client = client; > + > + ptn3222->reset_gpio = devm_gpiod_get_optional(dev, "reset", > + GPIOD_OUT_HIGH); > + if (IS_ERR(ptn3222->reset_gpio)) > + return dev_err_probe(dev, PTR_ERR(ptn3222->reset_gpio), > + "unable to acquire reset gpio\n"); > + > + ret = devm_regulator_bulk_get_const(dev, NUM_SUPPLIES, ptn3222_supplies, > + &ptn3222->supplies); > + if (ret) > + return ret; > + > + ptn3222->phy = devm_phy_create(dev, dev->of_node, &ptn3222_ops); > + if (IS_ERR(ptn3222->phy)) { > + dev_err(dev, "failed to create PHY: %d\n", ret); > + return PTR_ERR(ptn3222->phy); > + } > + > + phy_set_drvdata(ptn3222->phy, ptn3222); > + > + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); > + > + return PTR_ERR_OR_ZERO(phy_provider); > +} > + > +static const struct i2c_device_id ptn3222_table[] = { > + { "ptn3222" }, > + { } > +}; > +MODULE_DEVICE_TABLE(i2c, ptn3222_table); > + > +static const struct of_device_id ptn3222_of_table[] = { > + { .compatible = "nxp,ptn3222" }, > + { } > +}; > +MODULE_DEVICE_TABLE(of, ptn3222_of_table); > + > +static struct i2c_driver ptn3222_driver = { > + .driver = { > + .name = "ptn3222", > + .of_match_table = ptn3222_of_table, > + }, > + .probe = ptn3222_probe, > + .id_table = ptn3222_table, > +}; > + > +module_i2c_driver(ptn3222_driver); > + > +MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); > +MODULE_LICENSE("GPL"); > > -- > 2.39.2 >
diff --git a/drivers/phy/Kconfig b/drivers/phy/Kconfig index dfab1c66b3e5..cb06a7f79740 100644 --- a/drivers/phy/Kconfig +++ b/drivers/phy/Kconfig @@ -82,6 +82,17 @@ config PHY_AIROHA_PCIE This driver create the basic PHY instance and provides initialize callback for PCIe GEN3 port. +config PHY_NXP_PTN3222 + tristate "NXP PTN3222 1-port eUSB2 to USB2 redriver" + depends on I2C + depends on OF + select GENERIC_PHY + help + Enable this to support NXP PTN3222 1-port eUSB2 to USB2 Redriver. + This redriver performs translation between eUSB2 and USB2 signalling + schemes. It supports all three USB 2.0 data rates: Low Speed, Full + Speed and High Speed. + source "drivers/phy/allwinner/Kconfig" source "drivers/phy/amlogic/Kconfig" source "drivers/phy/broadcom/Kconfig" diff --git a/drivers/phy/Makefile b/drivers/phy/Makefile index 5fcbce5f9ab1..b64247046575 100644 --- a/drivers/phy/Makefile +++ b/drivers/phy/Makefile @@ -11,6 +11,7 @@ obj-$(CONFIG_PHY_XGENE) += phy-xgene.o obj-$(CONFIG_PHY_PISTACHIO_USB) += phy-pistachio-usb.o obj-$(CONFIG_USB_LGM_PHY) += phy-lgm-usb.o obj-$(CONFIG_PHY_AIROHA_PCIE) += phy-airoha-pcie.o +obj-$(CONFIG_PHY_NXP_PTN3222) += phy-nxp-ptn3222.o obj-y += allwinner/ \ amlogic/ \ broadcom/ \ diff --git a/drivers/phy/phy-nxp-ptn3222.c b/drivers/phy/phy-nxp-ptn3222.c new file mode 100644 index 000000000000..c6179d8701e6 --- /dev/null +++ b/drivers/phy/phy-nxp-ptn3222.c @@ -0,0 +1,123 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright (c) 2024, Linaro Limited + */ + +#include <linux/gpio/consumer.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/of.h> +#include <linux/phy/phy.h> +#include <linux/regmap.h> +#include <linux/regulator/consumer.h> + +#define NUM_SUPPLIES 2 + +struct ptn3222 { + struct i2c_client *client; + struct phy *phy; + struct gpio_desc *reset_gpio; + struct regulator_bulk_data *supplies; +}; + +static int ptn3222_init(struct phy *phy) +{ + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); + int ret; + + ret = regulator_bulk_enable(NUM_SUPPLIES, ptn3222->supplies); + if (ret) + return ret; + + gpiod_set_value_cansleep(ptn3222->reset_gpio, 0); + + return 0; +} + +static int ptn3222_exit(struct phy *phy) +{ + struct ptn3222 *ptn3222 = phy_get_drvdata(phy); + + gpiod_set_value_cansleep(ptn3222->reset_gpio, 1); + + return regulator_bulk_disable(NUM_SUPPLIES, ptn3222->supplies); +} + +static const struct phy_ops ptn3222_ops = { + .init = ptn3222_init, + .exit = ptn3222_exit, + .owner = THIS_MODULE, +}; + +static const struct regulator_bulk_data ptn3222_supplies[NUM_SUPPLIES] = { + { + .supply = "vdd3v3", + .init_load_uA = 11000, + }, { + .supply = "vdd1v8", + .init_load_uA = 55000, + } +}; + +static int ptn3222_probe(struct i2c_client *client) +{ + struct device *dev = &client->dev; + struct phy_provider *phy_provider; + struct ptn3222 *ptn3222; + int ret; + + ptn3222 = devm_kzalloc(dev, sizeof(*ptn3222), GFP_KERNEL); + if (!ptn3222) + return -ENOMEM; + + ptn3222->client = client; + + ptn3222->reset_gpio = devm_gpiod_get_optional(dev, "reset", + GPIOD_OUT_HIGH); + if (IS_ERR(ptn3222->reset_gpio)) + return dev_err_probe(dev, PTR_ERR(ptn3222->reset_gpio), + "unable to acquire reset gpio\n"); + + ret = devm_regulator_bulk_get_const(dev, NUM_SUPPLIES, ptn3222_supplies, + &ptn3222->supplies); + if (ret) + return ret; + + ptn3222->phy = devm_phy_create(dev, dev->of_node, &ptn3222_ops); + if (IS_ERR(ptn3222->phy)) { + dev_err(dev, "failed to create PHY: %d\n", ret); + return PTR_ERR(ptn3222->phy); + } + + phy_set_drvdata(ptn3222->phy, ptn3222); + + phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); + + return PTR_ERR_OR_ZERO(phy_provider); +} + +static const struct i2c_device_id ptn3222_table[] = { + { "ptn3222" }, + { } +}; +MODULE_DEVICE_TABLE(i2c, ptn3222_table); + +static const struct of_device_id ptn3222_of_table[] = { + { .compatible = "nxp,ptn3222" }, + { } +}; +MODULE_DEVICE_TABLE(of, ptn3222_of_table); + +static struct i2c_driver ptn3222_driver = { + .driver = { + .name = "ptn3222", + .of_match_table = ptn3222_of_table, + }, + .probe = ptn3222_probe, + .id_table = ptn3222_table, +}; + +module_i2c_driver(ptn3222_driver); + +MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); +MODULE_LICENSE("GPL");