123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993 |
- /*
- * Copyright (c) 2014, NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- */
- #include <linux/delay.h>
- #include <linux/io.h>
- #include <linux/module.h>
- #include <linux/of.h>
- #include <linux/phy/phy.h>
- #include <linux/pinctrl/pinctrl.h>
- #include <linux/pinctrl/pinmux.h>
- #include <linux/platform_device.h>
- #include <linux/reset.h>
- #include <linux/slab.h>
- #include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
- #include "core.h"
- #include "pinctrl-utils.h"
- #define XUSB_PADCTL_ELPG_PROGRAM 0x01c
- #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN (1 << 26)
- #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY (1 << 25)
- #define XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN (1 << 24)
- #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1 0x040
- #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET (1 << 19)
- #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK (0xf << 12)
- #define XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST (1 << 1)
- #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2 0x044
- #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN (1 << 6)
- #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN (1 << 5)
- #define XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL (1 << 4)
- #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1 0x138
- #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET (1 << 27)
- #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE (1 << 24)
- #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD (1 << 3)
- #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST (1 << 1)
- #define XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ (1 << 0)
- #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1 0x148
- #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD (1 << 1)
- #define XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ (1 << 0)
- struct tegra_xusb_padctl_function {
- const char *name;
- const char * const *groups;
- unsigned int num_groups;
- };
- struct tegra_xusb_padctl_soc {
- const struct pinctrl_pin_desc *pins;
- unsigned int num_pins;
- const struct tegra_xusb_padctl_function *functions;
- unsigned int num_functions;
- const struct tegra_xusb_padctl_lane *lanes;
- unsigned int num_lanes;
- };
- struct tegra_xusb_padctl_lane {
- const char *name;
- unsigned int offset;
- unsigned int shift;
- unsigned int mask;
- unsigned int iddq;
- const unsigned int *funcs;
- unsigned int num_funcs;
- };
- struct tegra_xusb_padctl {
- struct device *dev;
- void __iomem *regs;
- struct mutex lock;
- struct reset_control *rst;
- const struct tegra_xusb_padctl_soc *soc;
- struct pinctrl_dev *pinctrl;
- struct pinctrl_desc desc;
- struct phy_provider *provider;
- struct phy *phys[2];
- unsigned int enable;
- };
- static inline void padctl_writel(struct tegra_xusb_padctl *padctl, u32 value,
- unsigned long offset)
- {
- writel(value, padctl->regs + offset);
- }
- static inline u32 padctl_readl(struct tegra_xusb_padctl *padctl,
- unsigned long offset)
- {
- return readl(padctl->regs + offset);
- }
- static int tegra_xusb_padctl_get_groups_count(struct pinctrl_dev *pinctrl)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- return padctl->soc->num_pins;
- }
- static const char *tegra_xusb_padctl_get_group_name(struct pinctrl_dev *pinctrl,
- unsigned int group)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- return padctl->soc->pins[group].name;
- }
- static int tegra_xusb_padctl_get_group_pins(struct pinctrl_dev *pinctrl,
- unsigned group,
- const unsigned **pins,
- unsigned *num_pins)
- {
- /*
- * For the tegra-xusb pad controller groups are synonomous
- * with lanes/pins and there is always one lane/pin per group.
- */
- *pins = &pinctrl->desc->pins[group].number;
- *num_pins = 1;
- return 0;
- }
- enum tegra_xusb_padctl_param {
- TEGRA_XUSB_PADCTL_IDDQ,
- };
- static const struct tegra_xusb_padctl_property {
- const char *name;
- enum tegra_xusb_padctl_param param;
- } properties[] = {
- { "nvidia,iddq", TEGRA_XUSB_PADCTL_IDDQ },
- };
- #define TEGRA_XUSB_PADCTL_PACK(param, value) ((param) << 16 | (value))
- #define TEGRA_XUSB_PADCTL_UNPACK_PARAM(config) ((config) >> 16)
- #define TEGRA_XUSB_PADCTL_UNPACK_VALUE(config) ((config) & 0xffff)
- static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl,
- struct device_node *np,
- struct pinctrl_map **maps,
- unsigned int *reserved_maps,
- unsigned int *num_maps)
- {
- unsigned int i, reserve = 0, num_configs = 0;
- unsigned long config, *configs = NULL;
- const char *function, *group;
- struct property *prop;
- int err = 0;
- u32 value;
- err = of_property_read_string(np, "nvidia,function", &function);
- if (err < 0) {
- if (err != -EINVAL)
- return err;
- function = NULL;
- }
- for (i = 0; i < ARRAY_SIZE(properties); i++) {
- err = of_property_read_u32(np, properties[i].name, &value);
- if (err < 0) {
- if (err == -EINVAL)
- continue;
- goto out;
- }
- config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, value);
- err = pinctrl_utils_add_config(padctl->pinctrl, &configs,
- &num_configs, config);
- if (err < 0)
- goto out;
- }
- if (function)
- reserve++;
- if (num_configs)
- reserve++;
- err = of_property_count_strings(np, "nvidia,lanes");
- if (err < 0)
- goto out;
- reserve *= err;
- err = pinctrl_utils_reserve_map(padctl->pinctrl, maps, reserved_maps,
- num_maps, reserve);
- if (err < 0)
- goto out;
- of_property_for_each_string(np, "nvidia,lanes", prop, group) {
- if (function) {
- err = pinctrl_utils_add_map_mux(padctl->pinctrl, maps,
- reserved_maps, num_maps, group,
- function);
- if (err < 0)
- goto out;
- }
- if (num_configs) {
- err = pinctrl_utils_add_map_configs(padctl->pinctrl,
- maps, reserved_maps, num_maps, group,
- configs, num_configs,
- PIN_MAP_TYPE_CONFIGS_GROUP);
- if (err < 0)
- goto out;
- }
- }
- err = 0;
- out:
- kfree(configs);
- return err;
- }
- static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl,
- struct device_node *parent,
- struct pinctrl_map **maps,
- unsigned int *num_maps)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- unsigned int reserved_maps = 0;
- struct device_node *np;
- int err;
- *num_maps = 0;
- *maps = NULL;
- for_each_child_of_node(parent, np) {
- err = tegra_xusb_padctl_parse_subnode(padctl, np, maps,
- &reserved_maps,
- num_maps);
- if (err < 0)
- return err;
- }
- return 0;
- }
- static const struct pinctrl_ops tegra_xusb_padctl_pinctrl_ops = {
- .get_groups_count = tegra_xusb_padctl_get_groups_count,
- .get_group_name = tegra_xusb_padctl_get_group_name,
- .get_group_pins = tegra_xusb_padctl_get_group_pins,
- .dt_node_to_map = tegra_xusb_padctl_dt_node_to_map,
- .dt_free_map = pinctrl_utils_dt_free_map,
- };
- static int tegra_xusb_padctl_get_functions_count(struct pinctrl_dev *pinctrl)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- return padctl->soc->num_functions;
- }
- static const char *
- tegra_xusb_padctl_get_function_name(struct pinctrl_dev *pinctrl,
- unsigned int function)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- return padctl->soc->functions[function].name;
- }
- static int tegra_xusb_padctl_get_function_groups(struct pinctrl_dev *pinctrl,
- unsigned int function,
- const char * const **groups,
- unsigned * const num_groups)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- *num_groups = padctl->soc->functions[function].num_groups;
- *groups = padctl->soc->functions[function].groups;
- return 0;
- }
- static int tegra_xusb_padctl_pinmux_set(struct pinctrl_dev *pinctrl,
- unsigned int function,
- unsigned int group)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- const struct tegra_xusb_padctl_lane *lane;
- unsigned int i;
- u32 value;
- lane = &padctl->soc->lanes[group];
- for (i = 0; i < lane->num_funcs; i++)
- if (lane->funcs[i] == function)
- break;
- if (i >= lane->num_funcs)
- return -EINVAL;
- value = padctl_readl(padctl, lane->offset);
- value &= ~(lane->mask << lane->shift);
- value |= i << lane->shift;
- padctl_writel(padctl, value, lane->offset);
- return 0;
- }
- static const struct pinmux_ops tegra_xusb_padctl_pinmux_ops = {
- .get_functions_count = tegra_xusb_padctl_get_functions_count,
- .get_function_name = tegra_xusb_padctl_get_function_name,
- .get_function_groups = tegra_xusb_padctl_get_function_groups,
- .set_mux = tegra_xusb_padctl_pinmux_set,
- };
- static int tegra_xusb_padctl_pinconf_group_get(struct pinctrl_dev *pinctrl,
- unsigned int group,
- unsigned long *config)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- const struct tegra_xusb_padctl_lane *lane;
- enum tegra_xusb_padctl_param param;
- u32 value;
- param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(*config);
- lane = &padctl->soc->lanes[group];
- switch (param) {
- case TEGRA_XUSB_PADCTL_IDDQ:
- /* lanes with iddq == 0 don't support this parameter */
- if (lane->iddq == 0)
- return -EINVAL;
- value = padctl_readl(padctl, lane->offset);
- if (value & BIT(lane->iddq))
- value = 0;
- else
- value = 1;
- *config = TEGRA_XUSB_PADCTL_PACK(param, value);
- break;
- default:
- dev_err(padctl->dev, "invalid configuration parameter: %04x\n",
- param);
- return -ENOTSUPP;
- }
- return 0;
- }
- static int tegra_xusb_padctl_pinconf_group_set(struct pinctrl_dev *pinctrl,
- unsigned int group,
- unsigned long *configs,
- unsigned int num_configs)
- {
- struct tegra_xusb_padctl *padctl = pinctrl_dev_get_drvdata(pinctrl);
- const struct tegra_xusb_padctl_lane *lane;
- enum tegra_xusb_padctl_param param;
- unsigned long value;
- unsigned int i;
- u32 regval;
- lane = &padctl->soc->lanes[group];
- for (i = 0; i < num_configs; i++) {
- param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(configs[i]);
- value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(configs[i]);
- switch (param) {
- case TEGRA_XUSB_PADCTL_IDDQ:
- /* lanes with iddq == 0 don't support this parameter */
- if (lane->iddq == 0)
- return -EINVAL;
- regval = padctl_readl(padctl, lane->offset);
- if (value)
- regval &= ~BIT(lane->iddq);
- else
- regval |= BIT(lane->iddq);
- padctl_writel(padctl, regval, lane->offset);
- break;
- default:
- dev_err(padctl->dev,
- "invalid configuration parameter: %04x\n",
- param);
- return -ENOTSUPP;
- }
- }
- return 0;
- }
- #ifdef CONFIG_DEBUG_FS
- static const char *strip_prefix(const char *s)
- {
- const char *comma = strchr(s, ',');
- if (!comma)
- return s;
- return comma + 1;
- }
- static void
- tegra_xusb_padctl_pinconf_group_dbg_show(struct pinctrl_dev *pinctrl,
- struct seq_file *s,
- unsigned int group)
- {
- unsigned int i;
- for (i = 0; i < ARRAY_SIZE(properties); i++) {
- unsigned long config, value;
- int err;
- config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, 0);
- err = tegra_xusb_padctl_pinconf_group_get(pinctrl, group,
- &config);
- if (err < 0)
- continue;
- value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(config);
- seq_printf(s, "\n\t%s=%lu\n", strip_prefix(properties[i].name),
- value);
- }
- }
- static void
- tegra_xusb_padctl_pinconf_config_dbg_show(struct pinctrl_dev *pinctrl,
- struct seq_file *s,
- unsigned long config)
- {
- enum tegra_xusb_padctl_param param;
- const char *name = "unknown";
- unsigned long value;
- unsigned int i;
- param = TEGRA_XUSB_PADCTL_UNPACK_PARAM(config);
- value = TEGRA_XUSB_PADCTL_UNPACK_VALUE(config);
- for (i = 0; i < ARRAY_SIZE(properties); i++) {
- if (properties[i].param == param) {
- name = properties[i].name;
- break;
- }
- }
- seq_printf(s, "%s=%lu", strip_prefix(name), value);
- }
- #endif
- static const struct pinconf_ops tegra_xusb_padctl_pinconf_ops = {
- .pin_config_group_get = tegra_xusb_padctl_pinconf_group_get,
- .pin_config_group_set = tegra_xusb_padctl_pinconf_group_set,
- #ifdef CONFIG_DEBUG_FS
- .pin_config_group_dbg_show = tegra_xusb_padctl_pinconf_group_dbg_show,
- .pin_config_config_dbg_show = tegra_xusb_padctl_pinconf_config_dbg_show,
- #endif
- };
- static int tegra_xusb_padctl_enable(struct tegra_xusb_padctl *padctl)
- {
- u32 value;
- mutex_lock(&padctl->lock);
- if (padctl->enable++ > 0)
- goto out;
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
- value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
- usleep_range(100, 200);
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
- value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
- usleep_range(100, 200);
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
- value &= ~XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
- out:
- mutex_unlock(&padctl->lock);
- return 0;
- }
- static int tegra_xusb_padctl_disable(struct tegra_xusb_padctl *padctl)
- {
- u32 value;
- mutex_lock(&padctl->lock);
- if (WARN_ON(padctl->enable == 0))
- goto out;
- if (--padctl->enable > 0)
- goto out;
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
- value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_VCORE_DOWN;
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
- usleep_range(100, 200);
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
- value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN_EARLY;
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
- usleep_range(100, 200);
- value = padctl_readl(padctl, XUSB_PADCTL_ELPG_PROGRAM);
- value |= XUSB_PADCTL_ELPG_PROGRAM_AUX_MUX_LP0_CLAMP_EN;
- padctl_writel(padctl, value, XUSB_PADCTL_ELPG_PROGRAM);
- out:
- mutex_unlock(&padctl->lock);
- return 0;
- }
- static int tegra_xusb_phy_init(struct phy *phy)
- {
- struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
- return tegra_xusb_padctl_enable(padctl);
- }
- static int tegra_xusb_phy_exit(struct phy *phy)
- {
- struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
- return tegra_xusb_padctl_disable(padctl);
- }
- static int pcie_phy_power_on(struct phy *phy)
- {
- struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
- unsigned long timeout;
- int err = -ETIMEDOUT;
- u32 value;
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
- value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_REFCLK_SEL_MASK;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
- value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL2_REFCLKBUF_EN |
- XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_EN |
- XUSB_PADCTL_IOPHY_PLL_P0_CTL2_TXCLKREF_SEL;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL2);
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
- value |= XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
- timeout = jiffies + msecs_to_jiffies(50);
- while (time_before(jiffies, timeout)) {
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
- if (value & XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL0_LOCKDET) {
- err = 0;
- break;
- }
- usleep_range(100, 200);
- }
- return err;
- }
- static int pcie_phy_power_off(struct phy *phy)
- {
- struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
- u32 value;
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
- value &= ~XUSB_PADCTL_IOPHY_PLL_P0_CTL1_PLL_RST;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_P0_CTL1);
- return 0;
- }
- static const struct phy_ops pcie_phy_ops = {
- .init = tegra_xusb_phy_init,
- .exit = tegra_xusb_phy_exit,
- .power_on = pcie_phy_power_on,
- .power_off = pcie_phy_power_off,
- .owner = THIS_MODULE,
- };
- static int sata_phy_power_on(struct phy *phy)
- {
- struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
- unsigned long timeout;
- int err = -ETIMEDOUT;
- u32 value;
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
- value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
- value &= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
- value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- timeout = jiffies + msecs_to_jiffies(50);
- while (time_before(jiffies, timeout)) {
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- if (value & XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_LOCKDET) {
- err = 0;
- break;
- }
- usleep_range(100, 200);
- }
- return err;
- }
- static int sata_phy_power_off(struct phy *phy)
- {
- struct tegra_xusb_padctl *padctl = phy_get_drvdata(phy);
- u32 value;
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_RST;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value &= ~XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL1_MODE;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_PWR_OVRD;
- value |= XUSB_PADCTL_IOPHY_PLL_S0_CTL1_PLL_IDDQ;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_PLL_S0_CTL1);
- value = padctl_readl(padctl, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
- value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ_OVRD;
- value |= ~XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1_IDDQ;
- padctl_writel(padctl, value, XUSB_PADCTL_IOPHY_MISC_PAD_S0_CTL1);
- return 0;
- }
- static const struct phy_ops sata_phy_ops = {
- .init = tegra_xusb_phy_init,
- .exit = tegra_xusb_phy_exit,
- .power_on = sata_phy_power_on,
- .power_off = sata_phy_power_off,
- .owner = THIS_MODULE,
- };
- static struct phy *tegra_xusb_padctl_xlate(struct device *dev,
- struct of_phandle_args *args)
- {
- struct tegra_xusb_padctl *padctl = dev_get_drvdata(dev);
- unsigned int index = args->args[0];
- if (args->args_count <= 0)
- return ERR_PTR(-EINVAL);
- if (index >= ARRAY_SIZE(padctl->phys))
- return ERR_PTR(-EINVAL);
- return padctl->phys[index];
- }
- #define PIN_OTG_0 0
- #define PIN_OTG_1 1
- #define PIN_OTG_2 2
- #define PIN_ULPI_0 3
- #define PIN_HSIC_0 4
- #define PIN_HSIC_1 5
- #define PIN_PCIE_0 6
- #define PIN_PCIE_1 7
- #define PIN_PCIE_2 8
- #define PIN_PCIE_3 9
- #define PIN_PCIE_4 10
- #define PIN_SATA_0 11
- static const struct pinctrl_pin_desc tegra124_pins[] = {
- PINCTRL_PIN(PIN_OTG_0, "otg-0"),
- PINCTRL_PIN(PIN_OTG_1, "otg-1"),
- PINCTRL_PIN(PIN_OTG_2, "otg-2"),
- PINCTRL_PIN(PIN_ULPI_0, "ulpi-0"),
- PINCTRL_PIN(PIN_HSIC_0, "hsic-0"),
- PINCTRL_PIN(PIN_HSIC_1, "hsic-1"),
- PINCTRL_PIN(PIN_PCIE_0, "pcie-0"),
- PINCTRL_PIN(PIN_PCIE_1, "pcie-1"),
- PINCTRL_PIN(PIN_PCIE_2, "pcie-2"),
- PINCTRL_PIN(PIN_PCIE_3, "pcie-3"),
- PINCTRL_PIN(PIN_PCIE_4, "pcie-4"),
- PINCTRL_PIN(PIN_SATA_0, "sata-0"),
- };
- static const char * const tegra124_snps_groups[] = {
- "otg-0",
- "otg-1",
- "otg-2",
- "ulpi-0",
- "hsic-0",
- "hsic-1",
- };
- static const char * const tegra124_xusb_groups[] = {
- "otg-0",
- "otg-1",
- "otg-2",
- "ulpi-0",
- "hsic-0",
- "hsic-1",
- };
- static const char * const tegra124_uart_groups[] = {
- "otg-0",
- "otg-1",
- "otg-2",
- };
- static const char * const tegra124_pcie_groups[] = {
- "pcie-0",
- "pcie-1",
- "pcie-2",
- "pcie-3",
- "pcie-4",
- "sata-0",
- };
- static const char * const tegra124_usb3_groups[] = {
- "pcie-0",
- "pcie-1",
- "pcie-2",
- "pcie-3",
- "pcie-4",
- "sata-0",
- };
- static const char * const tegra124_sata_groups[] = {
- "pcie-0",
- "pcie-1",
- "pcie-2",
- "pcie-3",
- "pcie-4",
- "sata-0",
- };
- static const char * const tegra124_rsvd_groups[] = {
- "otg-0",
- "otg-1",
- "otg-2",
- "pcie-0",
- "pcie-1",
- "pcie-2",
- "pcie-3",
- "pcie-4",
- "sata-0",
- };
- #define TEGRA124_FUNCTION(_name) \
- { \
- .name = #_name, \
- .num_groups = ARRAY_SIZE(tegra124_##_name##_groups), \
- .groups = tegra124_##_name##_groups, \
- }
- static struct tegra_xusb_padctl_function tegra124_functions[] = {
- TEGRA124_FUNCTION(snps),
- TEGRA124_FUNCTION(xusb),
- TEGRA124_FUNCTION(uart),
- TEGRA124_FUNCTION(pcie),
- TEGRA124_FUNCTION(usb3),
- TEGRA124_FUNCTION(sata),
- TEGRA124_FUNCTION(rsvd),
- };
- enum tegra124_function {
- TEGRA124_FUNC_SNPS,
- TEGRA124_FUNC_XUSB,
- TEGRA124_FUNC_UART,
- TEGRA124_FUNC_PCIE,
- TEGRA124_FUNC_USB3,
- TEGRA124_FUNC_SATA,
- TEGRA124_FUNC_RSVD,
- };
- static const unsigned int tegra124_otg_functions[] = {
- TEGRA124_FUNC_SNPS,
- TEGRA124_FUNC_XUSB,
- TEGRA124_FUNC_UART,
- TEGRA124_FUNC_RSVD,
- };
- static const unsigned int tegra124_usb_functions[] = {
- TEGRA124_FUNC_SNPS,
- TEGRA124_FUNC_XUSB,
- };
- static const unsigned int tegra124_pci_functions[] = {
- TEGRA124_FUNC_PCIE,
- TEGRA124_FUNC_USB3,
- TEGRA124_FUNC_SATA,
- TEGRA124_FUNC_RSVD,
- };
- #define TEGRA124_LANE(_name, _offset, _shift, _mask, _iddq, _funcs) \
- { \
- .name = _name, \
- .offset = _offset, \
- .shift = _shift, \
- .mask = _mask, \
- .iddq = _iddq, \
- .num_funcs = ARRAY_SIZE(tegra124_##_funcs##_functions), \
- .funcs = tegra124_##_funcs##_functions, \
- }
- static const struct tegra_xusb_padctl_lane tegra124_lanes[] = {
- TEGRA124_LANE("otg-0", 0x004, 0, 0x3, 0, otg),
- TEGRA124_LANE("otg-1", 0x004, 2, 0x3, 0, otg),
- TEGRA124_LANE("otg-2", 0x004, 4, 0x3, 0, otg),
- TEGRA124_LANE("ulpi-0", 0x004, 12, 0x1, 0, usb),
- TEGRA124_LANE("hsic-0", 0x004, 14, 0x1, 0, usb),
- TEGRA124_LANE("hsic-1", 0x004, 15, 0x1, 0, usb),
- TEGRA124_LANE("pcie-0", 0x134, 16, 0x3, 1, pci),
- TEGRA124_LANE("pcie-1", 0x134, 18, 0x3, 2, pci),
- TEGRA124_LANE("pcie-2", 0x134, 20, 0x3, 3, pci),
- TEGRA124_LANE("pcie-3", 0x134, 22, 0x3, 4, pci),
- TEGRA124_LANE("pcie-4", 0x134, 24, 0x3, 5, pci),
- TEGRA124_LANE("sata-0", 0x134, 26, 0x3, 6, pci),
- };
- static const struct tegra_xusb_padctl_soc tegra124_soc = {
- .num_pins = ARRAY_SIZE(tegra124_pins),
- .pins = tegra124_pins,
- .num_functions = ARRAY_SIZE(tegra124_functions),
- .functions = tegra124_functions,
- .num_lanes = ARRAY_SIZE(tegra124_lanes),
- .lanes = tegra124_lanes,
- };
- static const struct of_device_id tegra_xusb_padctl_of_match[] = {
- { .compatible = "nvidia,tegra124-xusb-padctl", .data = &tegra124_soc },
- { }
- };
- MODULE_DEVICE_TABLE(of, tegra_xusb_padctl_of_match);
- static int tegra_xusb_padctl_probe(struct platform_device *pdev)
- {
- struct tegra_xusb_padctl *padctl;
- const struct of_device_id *match;
- struct resource *res;
- struct phy *phy;
- int err;
- padctl = devm_kzalloc(&pdev->dev, sizeof(*padctl), GFP_KERNEL);
- if (!padctl)
- return -ENOMEM;
- platform_set_drvdata(pdev, padctl);
- mutex_init(&padctl->lock);
- padctl->dev = &pdev->dev;
- match = of_match_node(tegra_xusb_padctl_of_match, pdev->dev.of_node);
- padctl->soc = match->data;
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- padctl->regs = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(padctl->regs))
- return PTR_ERR(padctl->regs);
- padctl->rst = devm_reset_control_get(&pdev->dev, NULL);
- if (IS_ERR(padctl->rst))
- return PTR_ERR(padctl->rst);
- err = reset_control_deassert(padctl->rst);
- if (err < 0)
- return err;
- memset(&padctl->desc, 0, sizeof(padctl->desc));
- padctl->desc.name = dev_name(padctl->dev);
- padctl->desc.pins = tegra124_pins;
- padctl->desc.npins = ARRAY_SIZE(tegra124_pins);
- padctl->desc.pctlops = &tegra_xusb_padctl_pinctrl_ops;
- padctl->desc.pmxops = &tegra_xusb_padctl_pinmux_ops;
- padctl->desc.confops = &tegra_xusb_padctl_pinconf_ops;
- padctl->desc.owner = THIS_MODULE;
- padctl->pinctrl = pinctrl_register(&padctl->desc, &pdev->dev, padctl);
- if (IS_ERR(padctl->pinctrl)) {
- dev_err(&pdev->dev, "failed to register pincontrol\n");
- err = PTR_ERR(padctl->pinctrl);
- goto reset;
- }
- phy = devm_phy_create(&pdev->dev, NULL, &pcie_phy_ops);
- if (IS_ERR(phy)) {
- err = PTR_ERR(phy);
- goto unregister;
- }
- padctl->phys[TEGRA_XUSB_PADCTL_PCIE] = phy;
- phy_set_drvdata(phy, padctl);
- phy = devm_phy_create(&pdev->dev, NULL, &sata_phy_ops);
- if (IS_ERR(phy)) {
- err = PTR_ERR(phy);
- goto unregister;
- }
- padctl->phys[TEGRA_XUSB_PADCTL_SATA] = phy;
- phy_set_drvdata(phy, padctl);
- padctl->provider = devm_of_phy_provider_register(&pdev->dev,
- tegra_xusb_padctl_xlate);
- if (IS_ERR(padctl->provider)) {
- err = PTR_ERR(padctl->provider);
- dev_err(&pdev->dev, "failed to register PHYs: %d\n", err);
- goto unregister;
- }
- return 0;
- unregister:
- pinctrl_unregister(padctl->pinctrl);
- reset:
- reset_control_assert(padctl->rst);
- return err;
- }
- static int tegra_xusb_padctl_remove(struct platform_device *pdev)
- {
- struct tegra_xusb_padctl *padctl = platform_get_drvdata(pdev);
- int err;
- pinctrl_unregister(padctl->pinctrl);
- err = reset_control_assert(padctl->rst);
- if (err < 0)
- dev_err(&pdev->dev, "failed to assert reset: %d\n", err);
- return err;
- }
- static struct platform_driver tegra_xusb_padctl_driver = {
- .driver = {
- .name = "tegra-xusb-padctl",
- .of_match_table = tegra_xusb_padctl_of_match,
- },
- .probe = tegra_xusb_padctl_probe,
- .remove = tegra_xusb_padctl_remove,
- };
- module_platform_driver(tegra_xusb_padctl_driver);
- MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
- MODULE_DESCRIPTION("Tegra 124 XUSB Pad Control driver");
- MODULE_LICENSE("GPL v2");
|