cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

phy.c (5260B)


      1// SPDX-License-Identifier: GPL-2.0+
      2/*
      3 * A wrapper for multiple PHYs which passes all phy_* function calls to
      4 * multiple (actual) PHY devices. This is comes handy when initializing
      5 * all PHYs on a HCD and to keep them all in the same state.
      6 *
      7 * Copyright (C) 2018 Martin Blumenstingl <martin.blumenstingl@googlemail.com>
      8 */
      9
     10#include <linux/device.h>
     11#include <linux/list.h>
     12#include <linux/phy/phy.h>
     13#include <linux/of.h>
     14
     15#include "phy.h"
     16
     17struct usb_phy_roothub {
     18	struct phy		*phy;
     19	struct list_head	list;
     20};
     21
     22static int usb_phy_roothub_add_phy(struct device *dev, int index,
     23				   struct list_head *list)
     24{
     25	struct usb_phy_roothub *roothub_entry;
     26	struct phy *phy;
     27
     28	phy = devm_of_phy_get_by_index(dev, dev->of_node, index);
     29	if (IS_ERR(phy)) {
     30		if (PTR_ERR(phy) == -ENODEV)
     31			return 0;
     32		else
     33			return PTR_ERR(phy);
     34	}
     35
     36	roothub_entry = devm_kzalloc(dev, sizeof(*roothub_entry), GFP_KERNEL);
     37	if (!roothub_entry)
     38		return -ENOMEM;
     39
     40	INIT_LIST_HEAD(&roothub_entry->list);
     41
     42	roothub_entry->phy = phy;
     43
     44	list_add_tail(&roothub_entry->list, list);
     45
     46	return 0;
     47}
     48
     49struct usb_phy_roothub *usb_phy_roothub_alloc(struct device *dev)
     50{
     51	struct usb_phy_roothub *phy_roothub;
     52	int i, num_phys, err;
     53
     54	if (!IS_ENABLED(CONFIG_GENERIC_PHY))
     55		return NULL;
     56
     57	num_phys = of_count_phandle_with_args(dev->of_node, "phys",
     58					      "#phy-cells");
     59	if (num_phys <= 0)
     60		return NULL;
     61
     62	phy_roothub = devm_kzalloc(dev, sizeof(*phy_roothub), GFP_KERNEL);
     63	if (!phy_roothub)
     64		return ERR_PTR(-ENOMEM);
     65
     66	INIT_LIST_HEAD(&phy_roothub->list);
     67
     68	for (i = 0; i < num_phys; i++) {
     69		err = usb_phy_roothub_add_phy(dev, i, &phy_roothub->list);
     70		if (err)
     71			return ERR_PTR(err);
     72	}
     73
     74	return phy_roothub;
     75}
     76EXPORT_SYMBOL_GPL(usb_phy_roothub_alloc);
     77
     78int usb_phy_roothub_init(struct usb_phy_roothub *phy_roothub)
     79{
     80	struct usb_phy_roothub *roothub_entry;
     81	struct list_head *head;
     82	int err;
     83
     84	if (!phy_roothub)
     85		return 0;
     86
     87	head = &phy_roothub->list;
     88
     89	list_for_each_entry(roothub_entry, head, list) {
     90		err = phy_init(roothub_entry->phy);
     91		if (err)
     92			goto err_exit_phys;
     93	}
     94
     95	return 0;
     96
     97err_exit_phys:
     98	list_for_each_entry_continue_reverse(roothub_entry, head, list)
     99		phy_exit(roothub_entry->phy);
    100
    101	return err;
    102}
    103EXPORT_SYMBOL_GPL(usb_phy_roothub_init);
    104
    105int usb_phy_roothub_exit(struct usb_phy_roothub *phy_roothub)
    106{
    107	struct usb_phy_roothub *roothub_entry;
    108	struct list_head *head;
    109	int err, ret = 0;
    110
    111	if (!phy_roothub)
    112		return 0;
    113
    114	head = &phy_roothub->list;
    115
    116	list_for_each_entry(roothub_entry, head, list) {
    117		err = phy_exit(roothub_entry->phy);
    118		if (err)
    119			ret = err;
    120	}
    121
    122	return ret;
    123}
    124EXPORT_SYMBOL_GPL(usb_phy_roothub_exit);
    125
    126int usb_phy_roothub_set_mode(struct usb_phy_roothub *phy_roothub,
    127			     enum phy_mode mode)
    128{
    129	struct usb_phy_roothub *roothub_entry;
    130	struct list_head *head;
    131	int err;
    132
    133	if (!phy_roothub)
    134		return 0;
    135
    136	head = &phy_roothub->list;
    137
    138	list_for_each_entry(roothub_entry, head, list) {
    139		err = phy_set_mode(roothub_entry->phy, mode);
    140		if (err)
    141			goto err_out;
    142	}
    143
    144	return 0;
    145
    146err_out:
    147	list_for_each_entry_continue_reverse(roothub_entry, head, list)
    148		phy_power_off(roothub_entry->phy);
    149
    150	return err;
    151}
    152EXPORT_SYMBOL_GPL(usb_phy_roothub_set_mode);
    153
    154int usb_phy_roothub_calibrate(struct usb_phy_roothub *phy_roothub)
    155{
    156	struct usb_phy_roothub *roothub_entry;
    157	struct list_head *head;
    158	int err;
    159
    160	if (!phy_roothub)
    161		return 0;
    162
    163	head = &phy_roothub->list;
    164
    165	list_for_each_entry(roothub_entry, head, list) {
    166		err = phy_calibrate(roothub_entry->phy);
    167		if (err)
    168			return err;
    169	}
    170
    171	return 0;
    172}
    173EXPORT_SYMBOL_GPL(usb_phy_roothub_calibrate);
    174
    175int usb_phy_roothub_power_on(struct usb_phy_roothub *phy_roothub)
    176{
    177	struct usb_phy_roothub *roothub_entry;
    178	struct list_head *head;
    179	int err;
    180
    181	if (!phy_roothub)
    182		return 0;
    183
    184	head = &phy_roothub->list;
    185
    186	list_for_each_entry(roothub_entry, head, list) {
    187		err = phy_power_on(roothub_entry->phy);
    188		if (err)
    189			goto err_out;
    190	}
    191
    192	return 0;
    193
    194err_out:
    195	list_for_each_entry_continue_reverse(roothub_entry, head, list)
    196		phy_power_off(roothub_entry->phy);
    197
    198	return err;
    199}
    200EXPORT_SYMBOL_GPL(usb_phy_roothub_power_on);
    201
    202void usb_phy_roothub_power_off(struct usb_phy_roothub *phy_roothub)
    203{
    204	struct usb_phy_roothub *roothub_entry;
    205
    206	if (!phy_roothub)
    207		return;
    208
    209	list_for_each_entry_reverse(roothub_entry, &phy_roothub->list, list)
    210		phy_power_off(roothub_entry->phy);
    211}
    212EXPORT_SYMBOL_GPL(usb_phy_roothub_power_off);
    213
    214int usb_phy_roothub_suspend(struct device *controller_dev,
    215			    struct usb_phy_roothub *phy_roothub)
    216{
    217	usb_phy_roothub_power_off(phy_roothub);
    218
    219	/* keep the PHYs initialized so the device can wake up the system */
    220	if (device_may_wakeup(controller_dev))
    221		return 0;
    222
    223	return usb_phy_roothub_exit(phy_roothub);
    224}
    225EXPORT_SYMBOL_GPL(usb_phy_roothub_suspend);
    226
    227int usb_phy_roothub_resume(struct device *controller_dev,
    228			   struct usb_phy_roothub *phy_roothub)
    229{
    230	int err;
    231
    232	/* if the device can't wake up the system _exit was called */
    233	if (!device_may_wakeup(controller_dev)) {
    234		err = usb_phy_roothub_init(phy_roothub);
    235		if (err)
    236			return err;
    237	}
    238
    239	err = usb_phy_roothub_power_on(phy_roothub);
    240
    241	/* undo _init if _power_on failed */
    242	if (err && !device_may_wakeup(controller_dev))
    243		usb_phy_roothub_exit(phy_roothub);
    244
    245	return err;
    246}
    247EXPORT_SYMBOL_GPL(usb_phy_roothub_resume);