1*c9be539eSDmitry Baryshkov // SPDX-License-Identifier: GPL-2.0 2*c9be539eSDmitry Baryshkov /* 3*c9be539eSDmitry Baryshkov * Copyright (c) 2024, Linaro Limited 4*c9be539eSDmitry Baryshkov */ 5*c9be539eSDmitry Baryshkov 6*c9be539eSDmitry Baryshkov #include <linux/gpio/consumer.h> 7*c9be539eSDmitry Baryshkov #include <linux/i2c.h> 8*c9be539eSDmitry Baryshkov #include <linux/module.h> 9*c9be539eSDmitry Baryshkov #include <linux/of.h> 10*c9be539eSDmitry Baryshkov #include <linux/phy/phy.h> 11*c9be539eSDmitry Baryshkov #include <linux/regmap.h> 12*c9be539eSDmitry Baryshkov #include <linux/regulator/consumer.h> 13*c9be539eSDmitry Baryshkov 14*c9be539eSDmitry Baryshkov #define NUM_SUPPLIES 2 15*c9be539eSDmitry Baryshkov 16*c9be539eSDmitry Baryshkov struct ptn3222 { 17*c9be539eSDmitry Baryshkov struct i2c_client *client; 18*c9be539eSDmitry Baryshkov struct phy *phy; 19*c9be539eSDmitry Baryshkov struct gpio_desc *reset_gpio; 20*c9be539eSDmitry Baryshkov struct regulator_bulk_data *supplies; 21*c9be539eSDmitry Baryshkov }; 22*c9be539eSDmitry Baryshkov 23*c9be539eSDmitry Baryshkov static int ptn3222_init(struct phy *phy) 24*c9be539eSDmitry Baryshkov { 25*c9be539eSDmitry Baryshkov struct ptn3222 *ptn3222 = phy_get_drvdata(phy); 26*c9be539eSDmitry Baryshkov int ret; 27*c9be539eSDmitry Baryshkov 28*c9be539eSDmitry Baryshkov ret = regulator_bulk_enable(NUM_SUPPLIES, ptn3222->supplies); 29*c9be539eSDmitry Baryshkov if (ret) 30*c9be539eSDmitry Baryshkov return ret; 31*c9be539eSDmitry Baryshkov 32*c9be539eSDmitry Baryshkov gpiod_set_value_cansleep(ptn3222->reset_gpio, 0); 33*c9be539eSDmitry Baryshkov 34*c9be539eSDmitry Baryshkov return 0; 35*c9be539eSDmitry Baryshkov } 36*c9be539eSDmitry Baryshkov 37*c9be539eSDmitry Baryshkov static int ptn3222_exit(struct phy *phy) 38*c9be539eSDmitry Baryshkov { 39*c9be539eSDmitry Baryshkov struct ptn3222 *ptn3222 = phy_get_drvdata(phy); 40*c9be539eSDmitry Baryshkov 41*c9be539eSDmitry Baryshkov gpiod_set_value_cansleep(ptn3222->reset_gpio, 1); 42*c9be539eSDmitry Baryshkov 43*c9be539eSDmitry Baryshkov return regulator_bulk_disable(NUM_SUPPLIES, ptn3222->supplies); 44*c9be539eSDmitry Baryshkov } 45*c9be539eSDmitry Baryshkov 46*c9be539eSDmitry Baryshkov static const struct phy_ops ptn3222_ops = { 47*c9be539eSDmitry Baryshkov .init = ptn3222_init, 48*c9be539eSDmitry Baryshkov .exit = ptn3222_exit, 49*c9be539eSDmitry Baryshkov .owner = THIS_MODULE, 50*c9be539eSDmitry Baryshkov }; 51*c9be539eSDmitry Baryshkov 52*c9be539eSDmitry Baryshkov static const struct regulator_bulk_data ptn3222_supplies[NUM_SUPPLIES] = { 53*c9be539eSDmitry Baryshkov { 54*c9be539eSDmitry Baryshkov .supply = "vdd3v3", 55*c9be539eSDmitry Baryshkov .init_load_uA = 11000, 56*c9be539eSDmitry Baryshkov }, { 57*c9be539eSDmitry Baryshkov .supply = "vdd1v8", 58*c9be539eSDmitry Baryshkov .init_load_uA = 55000, 59*c9be539eSDmitry Baryshkov } 60*c9be539eSDmitry Baryshkov }; 61*c9be539eSDmitry Baryshkov 62*c9be539eSDmitry Baryshkov static int ptn3222_probe(struct i2c_client *client) 63*c9be539eSDmitry Baryshkov { 64*c9be539eSDmitry Baryshkov struct device *dev = &client->dev; 65*c9be539eSDmitry Baryshkov struct phy_provider *phy_provider; 66*c9be539eSDmitry Baryshkov struct ptn3222 *ptn3222; 67*c9be539eSDmitry Baryshkov int ret; 68*c9be539eSDmitry Baryshkov 69*c9be539eSDmitry Baryshkov ptn3222 = devm_kzalloc(dev, sizeof(*ptn3222), GFP_KERNEL); 70*c9be539eSDmitry Baryshkov if (!ptn3222) 71*c9be539eSDmitry Baryshkov return -ENOMEM; 72*c9be539eSDmitry Baryshkov 73*c9be539eSDmitry Baryshkov ptn3222->client = client; 74*c9be539eSDmitry Baryshkov 75*c9be539eSDmitry Baryshkov ptn3222->reset_gpio = devm_gpiod_get_optional(dev, "reset", 76*c9be539eSDmitry Baryshkov GPIOD_OUT_HIGH); 77*c9be539eSDmitry Baryshkov if (IS_ERR(ptn3222->reset_gpio)) 78*c9be539eSDmitry Baryshkov return dev_err_probe(dev, PTR_ERR(ptn3222->reset_gpio), 79*c9be539eSDmitry Baryshkov "unable to acquire reset gpio\n"); 80*c9be539eSDmitry Baryshkov 81*c9be539eSDmitry Baryshkov ret = devm_regulator_bulk_get_const(dev, NUM_SUPPLIES, ptn3222_supplies, 82*c9be539eSDmitry Baryshkov &ptn3222->supplies); 83*c9be539eSDmitry Baryshkov if (ret) 84*c9be539eSDmitry Baryshkov return ret; 85*c9be539eSDmitry Baryshkov 86*c9be539eSDmitry Baryshkov ptn3222->phy = devm_phy_create(dev, dev->of_node, &ptn3222_ops); 87*c9be539eSDmitry Baryshkov if (IS_ERR(ptn3222->phy)) { 88*c9be539eSDmitry Baryshkov dev_err(dev, "failed to create PHY: %d\n", ret); 89*c9be539eSDmitry Baryshkov return PTR_ERR(ptn3222->phy); 90*c9be539eSDmitry Baryshkov } 91*c9be539eSDmitry Baryshkov 92*c9be539eSDmitry Baryshkov phy_set_drvdata(ptn3222->phy, ptn3222); 93*c9be539eSDmitry Baryshkov 94*c9be539eSDmitry Baryshkov phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 95*c9be539eSDmitry Baryshkov 96*c9be539eSDmitry Baryshkov return PTR_ERR_OR_ZERO(phy_provider); 97*c9be539eSDmitry Baryshkov } 98*c9be539eSDmitry Baryshkov 99*c9be539eSDmitry Baryshkov static const struct i2c_device_id ptn3222_table[] = { 100*c9be539eSDmitry Baryshkov { "ptn3222" }, 101*c9be539eSDmitry Baryshkov { } 102*c9be539eSDmitry Baryshkov }; 103*c9be539eSDmitry Baryshkov MODULE_DEVICE_TABLE(i2c, ptn3222_table); 104*c9be539eSDmitry Baryshkov 105*c9be539eSDmitry Baryshkov static const struct of_device_id ptn3222_of_table[] = { 106*c9be539eSDmitry Baryshkov { .compatible = "nxp,ptn3222" }, 107*c9be539eSDmitry Baryshkov { } 108*c9be539eSDmitry Baryshkov }; 109*c9be539eSDmitry Baryshkov MODULE_DEVICE_TABLE(of, ptn3222_of_table); 110*c9be539eSDmitry Baryshkov 111*c9be539eSDmitry Baryshkov static struct i2c_driver ptn3222_driver = { 112*c9be539eSDmitry Baryshkov .driver = { 113*c9be539eSDmitry Baryshkov .name = "ptn3222", 114*c9be539eSDmitry Baryshkov .of_match_table = ptn3222_of_table, 115*c9be539eSDmitry Baryshkov }, 116*c9be539eSDmitry Baryshkov .probe = ptn3222_probe, 117*c9be539eSDmitry Baryshkov .id_table = ptn3222_table, 118*c9be539eSDmitry Baryshkov }; 119*c9be539eSDmitry Baryshkov 120*c9be539eSDmitry Baryshkov module_i2c_driver(ptn3222_driver); 121*c9be539eSDmitry Baryshkov 122*c9be539eSDmitry Baryshkov MODULE_DESCRIPTION("NXP PTN3222 eUSB2 Redriver driver"); 123*c9be539eSDmitry Baryshkov MODULE_LICENSE("GPL"); 124