summaryrefslogtreecommitdiff
path: root/drivers/phy/phy-nxp-ptn3222.c
blob: c6179d8701e61d22be2cf9c7bec983c56564aad2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
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");