171e2f5c5SKishon Vijay Abraham I // SPDX-License-Identifier: GPL-2.0 271e2f5c5SKishon Vijay Abraham I /** 371e2f5c5SKishon Vijay Abraham I * PCIe SERDES driver for AM654x SoC 471e2f5c5SKishon Vijay Abraham I * 571e2f5c5SKishon Vijay Abraham I * Copyright (C) 2018 - 2019 Texas Instruments Incorporated - http://www.ti.com/ 671e2f5c5SKishon Vijay Abraham I * Author: Kishon Vijay Abraham I <kishon@ti.com> 771e2f5c5SKishon Vijay Abraham I */ 871e2f5c5SKishon Vijay Abraham I 971e2f5c5SKishon Vijay Abraham I #include <dt-bindings/phy/phy.h> 1071e2f5c5SKishon Vijay Abraham I #include <linux/clk.h> 1171e2f5c5SKishon Vijay Abraham I #include <linux/clk-provider.h> 1271e2f5c5SKishon Vijay Abraham I #include <linux/delay.h> 1371e2f5c5SKishon Vijay Abraham I #include <linux/module.h> 1471e2f5c5SKishon Vijay Abraham I #include <linux/mfd/syscon.h> 1571e2f5c5SKishon Vijay Abraham I #include <linux/mux/consumer.h> 1671e2f5c5SKishon Vijay Abraham I #include <linux/of_address.h> 1771e2f5c5SKishon Vijay Abraham I #include <linux/phy/phy.h> 1871e2f5c5SKishon Vijay Abraham I #include <linux/platform_device.h> 1971e2f5c5SKishon Vijay Abraham I #include <linux/pm_runtime.h> 2071e2f5c5SKishon Vijay Abraham I #include <linux/regmap.h> 2171e2f5c5SKishon Vijay Abraham I 2271e2f5c5SKishon Vijay Abraham I #define CMU_R07C 0x7c 2371e2f5c5SKishon Vijay Abraham I 2471e2f5c5SKishon Vijay Abraham I #define COMLANE_R138 0xb38 2571e2f5c5SKishon Vijay Abraham I #define VERSION 0x70 2671e2f5c5SKishon Vijay Abraham I 2771e2f5c5SKishon Vijay Abraham I #define COMLANE_R190 0xb90 2871e2f5c5SKishon Vijay Abraham I 2971e2f5c5SKishon Vijay Abraham I #define COMLANE_R194 0xb94 3071e2f5c5SKishon Vijay Abraham I 3171e2f5c5SKishon Vijay Abraham I #define SERDES_CTRL 0x1fd0 3271e2f5c5SKishon Vijay Abraham I 3371e2f5c5SKishon Vijay Abraham I #define WIZ_LANEXCTL_STS 0x1fe0 3471e2f5c5SKishon Vijay Abraham I #define TX0_DISABLE_STATE 0x4 3571e2f5c5SKishon Vijay Abraham I #define TX0_SLEEP_STATE 0x5 3671e2f5c5SKishon Vijay Abraham I #define TX0_SNOOZE_STATE 0x6 3771e2f5c5SKishon Vijay Abraham I #define TX0_ENABLE_STATE 0x7 3871e2f5c5SKishon Vijay Abraham I 3971e2f5c5SKishon Vijay Abraham I #define RX0_DISABLE_STATE 0x4 4071e2f5c5SKishon Vijay Abraham I #define RX0_SLEEP_STATE 0x5 4171e2f5c5SKishon Vijay Abraham I #define RX0_SNOOZE_STATE 0x6 4271e2f5c5SKishon Vijay Abraham I #define RX0_ENABLE_STATE 0x7 4371e2f5c5SKishon Vijay Abraham I 4471e2f5c5SKishon Vijay Abraham I #define WIZ_PLL_CTRL 0x1ff4 4571e2f5c5SKishon Vijay Abraham I #define PLL_DISABLE_STATE 0x4 4671e2f5c5SKishon Vijay Abraham I #define PLL_SLEEP_STATE 0x5 4771e2f5c5SKishon Vijay Abraham I #define PLL_SNOOZE_STATE 0x6 4871e2f5c5SKishon Vijay Abraham I #define PLL_ENABLE_STATE 0x7 4971e2f5c5SKishon Vijay Abraham I 5071e2f5c5SKishon Vijay Abraham I #define PLL_LOCK_TIME 100000 /* in microseconds */ 5171e2f5c5SKishon Vijay Abraham I #define SLEEP_TIME 100 /* in microseconds */ 5271e2f5c5SKishon Vijay Abraham I 5371e2f5c5SKishon Vijay Abraham I #define LANE_USB3 0x0 5471e2f5c5SKishon Vijay Abraham I #define LANE_PCIE0_LANE0 0x1 5571e2f5c5SKishon Vijay Abraham I 5671e2f5c5SKishon Vijay Abraham I #define LANE_PCIE1_LANE0 0x0 5771e2f5c5SKishon Vijay Abraham I #define LANE_PCIE0_LANE1 0x1 5871e2f5c5SKishon Vijay Abraham I 5971e2f5c5SKishon Vijay Abraham I #define SERDES_NUM_CLOCKS 3 6071e2f5c5SKishon Vijay Abraham I 617e7b8ca6SRoger Quadros #define AM654_SERDES_CTRL_CLKSEL_MASK GENMASK(7, 4) 627e7b8ca6SRoger Quadros #define AM654_SERDES_CTRL_CLKSEL_SHIFT 4 637e7b8ca6SRoger Quadros 6471e2f5c5SKishon Vijay Abraham I struct serdes_am654_clk_mux { 6571e2f5c5SKishon Vijay Abraham I struct clk_hw hw; 6671e2f5c5SKishon Vijay Abraham I struct regmap *regmap; 6771e2f5c5SKishon Vijay Abraham I unsigned int reg; 687e7b8ca6SRoger Quadros int clk_id; 6971e2f5c5SKishon Vijay Abraham I struct clk_init_data clk_data; 7071e2f5c5SKishon Vijay Abraham I }; 7171e2f5c5SKishon Vijay Abraham I 7271e2f5c5SKishon Vijay Abraham I #define to_serdes_am654_clk_mux(_hw) \ 7371e2f5c5SKishon Vijay Abraham I container_of(_hw, struct serdes_am654_clk_mux, hw) 7471e2f5c5SKishon Vijay Abraham I 750cb5ebc7SRikard Falkeborn static const struct regmap_config serdes_am654_regmap_config = { 7671e2f5c5SKishon Vijay Abraham I .reg_bits = 32, 7771e2f5c5SKishon Vijay Abraham I .val_bits = 32, 7871e2f5c5SKishon Vijay Abraham I .reg_stride = 4, 7971e2f5c5SKishon Vijay Abraham I .fast_io = true, 8024dcb6a6SRoger Quadros .max_register = 0x1ffc, 8171e2f5c5SKishon Vijay Abraham I }; 8271e2f5c5SKishon Vijay Abraham I 8371e2f5c5SKishon Vijay Abraham I static const struct reg_field cmu_master_cdn_o = REG_FIELD(CMU_R07C, 24, 24); 8471e2f5c5SKishon Vijay Abraham I static const struct reg_field config_version = REG_FIELD(COMLANE_R138, 16, 23); 8571e2f5c5SKishon Vijay Abraham I static const struct reg_field l1_master_cdn_o = REG_FIELD(COMLANE_R190, 9, 9); 8671e2f5c5SKishon Vijay Abraham I static const struct reg_field cmu_ok_i_0 = REG_FIELD(COMLANE_R194, 19, 19); 8771e2f5c5SKishon Vijay Abraham I static const struct reg_field por_en = REG_FIELD(SERDES_CTRL, 29, 29); 8871e2f5c5SKishon Vijay Abraham I static const struct reg_field tx0_enable = REG_FIELD(WIZ_LANEXCTL_STS, 29, 31); 8971e2f5c5SKishon Vijay Abraham I static const struct reg_field rx0_enable = REG_FIELD(WIZ_LANEXCTL_STS, 13, 15); 9071e2f5c5SKishon Vijay Abraham I static const struct reg_field pll_enable = REG_FIELD(WIZ_PLL_CTRL, 29, 31); 9171e2f5c5SKishon Vijay Abraham I static const struct reg_field pll_ok = REG_FIELD(WIZ_PLL_CTRL, 28, 28); 9271e2f5c5SKishon Vijay Abraham I 9371e2f5c5SKishon Vijay Abraham I struct serdes_am654 { 9471e2f5c5SKishon Vijay Abraham I struct regmap *regmap; 9571e2f5c5SKishon Vijay Abraham I struct regmap_field *cmu_master_cdn_o; 9671e2f5c5SKishon Vijay Abraham I struct regmap_field *config_version; 9771e2f5c5SKishon Vijay Abraham I struct regmap_field *l1_master_cdn_o; 9871e2f5c5SKishon Vijay Abraham I struct regmap_field *cmu_ok_i_0; 9971e2f5c5SKishon Vijay Abraham I struct regmap_field *por_en; 10071e2f5c5SKishon Vijay Abraham I struct regmap_field *tx0_enable; 10171e2f5c5SKishon Vijay Abraham I struct regmap_field *rx0_enable; 10271e2f5c5SKishon Vijay Abraham I struct regmap_field *pll_enable; 10371e2f5c5SKishon Vijay Abraham I struct regmap_field *pll_ok; 10471e2f5c5SKishon Vijay Abraham I 10571e2f5c5SKishon Vijay Abraham I struct device *dev; 10671e2f5c5SKishon Vijay Abraham I struct mux_control *control; 10771e2f5c5SKishon Vijay Abraham I bool busy; 10871e2f5c5SKishon Vijay Abraham I u32 type; 10971e2f5c5SKishon Vijay Abraham I struct device_node *of_node; 11071e2f5c5SKishon Vijay Abraham I struct clk_onecell_data clk_data; 11171e2f5c5SKishon Vijay Abraham I struct clk *clks[SERDES_NUM_CLOCKS]; 11271e2f5c5SKishon Vijay Abraham I }; 11371e2f5c5SKishon Vijay Abraham I 11471e2f5c5SKishon Vijay Abraham I static int serdes_am654_enable_pll(struct serdes_am654 *phy) 11571e2f5c5SKishon Vijay Abraham I { 11671e2f5c5SKishon Vijay Abraham I int ret; 11771e2f5c5SKishon Vijay Abraham I u32 val; 11871e2f5c5SKishon Vijay Abraham I 11971e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->pll_enable, PLL_ENABLE_STATE); 12071e2f5c5SKishon Vijay Abraham I if (ret) 12171e2f5c5SKishon Vijay Abraham I return ret; 12271e2f5c5SKishon Vijay Abraham I 12371e2f5c5SKishon Vijay Abraham I return regmap_field_read_poll_timeout(phy->pll_ok, val, val, 1000, 12471e2f5c5SKishon Vijay Abraham I PLL_LOCK_TIME); 12571e2f5c5SKishon Vijay Abraham I } 12671e2f5c5SKishon Vijay Abraham I 12771e2f5c5SKishon Vijay Abraham I static void serdes_am654_disable_pll(struct serdes_am654 *phy) 12871e2f5c5SKishon Vijay Abraham I { 12971e2f5c5SKishon Vijay Abraham I struct device *dev = phy->dev; 13071e2f5c5SKishon Vijay Abraham I int ret; 13171e2f5c5SKishon Vijay Abraham I 13271e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->pll_enable, PLL_DISABLE_STATE); 13371e2f5c5SKishon Vijay Abraham I if (ret) 13471e2f5c5SKishon Vijay Abraham I dev_err(dev, "Failed to disable PLL\n"); 13571e2f5c5SKishon Vijay Abraham I } 13671e2f5c5SKishon Vijay Abraham I 13771e2f5c5SKishon Vijay Abraham I static int serdes_am654_enable_txrx(struct serdes_am654 *phy) 13871e2f5c5SKishon Vijay Abraham I { 13971e2f5c5SKishon Vijay Abraham I int ret; 14071e2f5c5SKishon Vijay Abraham I 14171e2f5c5SKishon Vijay Abraham I /* Enable TX */ 14271e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->tx0_enable, TX0_ENABLE_STATE); 14371e2f5c5SKishon Vijay Abraham I if (ret) 14471e2f5c5SKishon Vijay Abraham I return ret; 14571e2f5c5SKishon Vijay Abraham I 14671e2f5c5SKishon Vijay Abraham I /* Enable RX */ 14771e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->rx0_enable, RX0_ENABLE_STATE); 14871e2f5c5SKishon Vijay Abraham I if (ret) 14971e2f5c5SKishon Vijay Abraham I return ret; 15071e2f5c5SKishon Vijay Abraham I 15171e2f5c5SKishon Vijay Abraham I return 0; 15271e2f5c5SKishon Vijay Abraham I } 15371e2f5c5SKishon Vijay Abraham I 15471e2f5c5SKishon Vijay Abraham I static int serdes_am654_disable_txrx(struct serdes_am654 *phy) 15571e2f5c5SKishon Vijay Abraham I { 15671e2f5c5SKishon Vijay Abraham I int ret; 15771e2f5c5SKishon Vijay Abraham I 15871e2f5c5SKishon Vijay Abraham I /* Disable TX */ 15971e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->tx0_enable, TX0_DISABLE_STATE); 16071e2f5c5SKishon Vijay Abraham I if (ret) 16171e2f5c5SKishon Vijay Abraham I return ret; 16271e2f5c5SKishon Vijay Abraham I 16371e2f5c5SKishon Vijay Abraham I /* Disable RX */ 16471e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->rx0_enable, RX0_DISABLE_STATE); 16571e2f5c5SKishon Vijay Abraham I if (ret) 16671e2f5c5SKishon Vijay Abraham I return ret; 16771e2f5c5SKishon Vijay Abraham I 16871e2f5c5SKishon Vijay Abraham I return 0; 16971e2f5c5SKishon Vijay Abraham I } 17071e2f5c5SKishon Vijay Abraham I 17171e2f5c5SKishon Vijay Abraham I static int serdes_am654_power_on(struct phy *x) 17271e2f5c5SKishon Vijay Abraham I { 17371e2f5c5SKishon Vijay Abraham I struct serdes_am654 *phy = phy_get_drvdata(x); 17471e2f5c5SKishon Vijay Abraham I struct device *dev = phy->dev; 17571e2f5c5SKishon Vijay Abraham I int ret; 17671e2f5c5SKishon Vijay Abraham I u32 val; 17771e2f5c5SKishon Vijay Abraham I 17871e2f5c5SKishon Vijay Abraham I ret = serdes_am654_enable_pll(phy); 17971e2f5c5SKishon Vijay Abraham I if (ret) { 18071e2f5c5SKishon Vijay Abraham I dev_err(dev, "Failed to enable PLL\n"); 18171e2f5c5SKishon Vijay Abraham I return ret; 18271e2f5c5SKishon Vijay Abraham I } 18371e2f5c5SKishon Vijay Abraham I 18471e2f5c5SKishon Vijay Abraham I ret = serdes_am654_enable_txrx(phy); 18571e2f5c5SKishon Vijay Abraham I if (ret) { 18671e2f5c5SKishon Vijay Abraham I dev_err(dev, "Failed to enable TX RX\n"); 18771e2f5c5SKishon Vijay Abraham I return ret; 18871e2f5c5SKishon Vijay Abraham I } 18971e2f5c5SKishon Vijay Abraham I 19071e2f5c5SKishon Vijay Abraham I return regmap_field_read_poll_timeout(phy->cmu_ok_i_0, val, val, 19171e2f5c5SKishon Vijay Abraham I SLEEP_TIME, PLL_LOCK_TIME); 19271e2f5c5SKishon Vijay Abraham I } 19371e2f5c5SKishon Vijay Abraham I 19471e2f5c5SKishon Vijay Abraham I static int serdes_am654_power_off(struct phy *x) 19571e2f5c5SKishon Vijay Abraham I { 19671e2f5c5SKishon Vijay Abraham I struct serdes_am654 *phy = phy_get_drvdata(x); 19771e2f5c5SKishon Vijay Abraham I 19871e2f5c5SKishon Vijay Abraham I serdes_am654_disable_txrx(phy); 19971e2f5c5SKishon Vijay Abraham I serdes_am654_disable_pll(phy); 20071e2f5c5SKishon Vijay Abraham I 20171e2f5c5SKishon Vijay Abraham I return 0; 20271e2f5c5SKishon Vijay Abraham I } 20371e2f5c5SKishon Vijay Abraham I 204257d0be3SRoger Quadros #define SERDES_AM654_CFG(offset, a, b, val) \ 205257d0be3SRoger Quadros regmap_update_bits(phy->regmap, (offset),\ 206257d0be3SRoger Quadros GENMASK((a), (b)), (val) << (b)) 207257d0be3SRoger Quadros 208257d0be3SRoger Quadros static int serdes_am654_usb3_init(struct serdes_am654 *phy) 20971e2f5c5SKishon Vijay Abraham I { 210257d0be3SRoger Quadros SERDES_AM654_CFG(0x0000, 31, 24, 0x17); 211257d0be3SRoger Quadros SERDES_AM654_CFG(0x0004, 15, 8, 0x02); 212257d0be3SRoger Quadros SERDES_AM654_CFG(0x0004, 7, 0, 0x0e); 213257d0be3SRoger Quadros SERDES_AM654_CFG(0x0008, 23, 16, 0x2e); 214257d0be3SRoger Quadros SERDES_AM654_CFG(0x0008, 31, 24, 0x2e); 215257d0be3SRoger Quadros SERDES_AM654_CFG(0x0060, 7, 0, 0x4b); 216257d0be3SRoger Quadros SERDES_AM654_CFG(0x0060, 15, 8, 0x98); 217257d0be3SRoger Quadros SERDES_AM654_CFG(0x0060, 23, 16, 0x60); 218257d0be3SRoger Quadros SERDES_AM654_CFG(0x00d0, 31, 24, 0x45); 219257d0be3SRoger Quadros SERDES_AM654_CFG(0x00e8, 15, 8, 0x0e); 220257d0be3SRoger Quadros SERDES_AM654_CFG(0x0220, 7, 0, 0x34); 221257d0be3SRoger Quadros SERDES_AM654_CFG(0x0220, 15, 8, 0x34); 222257d0be3SRoger Quadros SERDES_AM654_CFG(0x0220, 31, 24, 0x37); 223257d0be3SRoger Quadros SERDES_AM654_CFG(0x0224, 7, 0, 0x37); 224257d0be3SRoger Quadros SERDES_AM654_CFG(0x0224, 15, 8, 0x37); 225257d0be3SRoger Quadros SERDES_AM654_CFG(0x0228, 23, 16, 0x37); 226257d0be3SRoger Quadros SERDES_AM654_CFG(0x0228, 31, 24, 0x37); 227257d0be3SRoger Quadros SERDES_AM654_CFG(0x022c, 7, 0, 0x37); 228257d0be3SRoger Quadros SERDES_AM654_CFG(0x022c, 15, 8, 0x37); 229257d0be3SRoger Quadros SERDES_AM654_CFG(0x0230, 15, 8, 0x2a); 230257d0be3SRoger Quadros SERDES_AM654_CFG(0x0230, 23, 16, 0x2a); 231257d0be3SRoger Quadros SERDES_AM654_CFG(0x0240, 23, 16, 0x10); 232257d0be3SRoger Quadros SERDES_AM654_CFG(0x0240, 31, 24, 0x34); 233257d0be3SRoger Quadros SERDES_AM654_CFG(0x0244, 7, 0, 0x40); 234257d0be3SRoger Quadros SERDES_AM654_CFG(0x0244, 23, 16, 0x34); 235257d0be3SRoger Quadros SERDES_AM654_CFG(0x0248, 15, 8, 0x0d); 236257d0be3SRoger Quadros SERDES_AM654_CFG(0x0258, 15, 8, 0x16); 237257d0be3SRoger Quadros SERDES_AM654_CFG(0x0258, 23, 16, 0x84); 238257d0be3SRoger Quadros SERDES_AM654_CFG(0x0258, 31, 24, 0xf2); 239257d0be3SRoger Quadros SERDES_AM654_CFG(0x025c, 7, 0, 0x21); 240257d0be3SRoger Quadros SERDES_AM654_CFG(0x0260, 7, 0, 0x27); 241257d0be3SRoger Quadros SERDES_AM654_CFG(0x0260, 15, 8, 0x04); 242257d0be3SRoger Quadros SERDES_AM654_CFG(0x0268, 15, 8, 0x04); 243257d0be3SRoger Quadros SERDES_AM654_CFG(0x0288, 15, 8, 0x2c); 244257d0be3SRoger Quadros SERDES_AM654_CFG(0x0330, 31, 24, 0xa0); 245257d0be3SRoger Quadros SERDES_AM654_CFG(0x0338, 23, 16, 0x03); 246257d0be3SRoger Quadros SERDES_AM654_CFG(0x0338, 31, 24, 0x00); 247257d0be3SRoger Quadros SERDES_AM654_CFG(0x033c, 7, 0, 0x00); 248257d0be3SRoger Quadros SERDES_AM654_CFG(0x0344, 31, 24, 0x18); 249257d0be3SRoger Quadros SERDES_AM654_CFG(0x034c, 7, 0, 0x18); 250257d0be3SRoger Quadros SERDES_AM654_CFG(0x039c, 23, 16, 0x3b); 251257d0be3SRoger Quadros SERDES_AM654_CFG(0x0a04, 7, 0, 0x03); 252257d0be3SRoger Quadros SERDES_AM654_CFG(0x0a14, 31, 24, 0x3c); 253257d0be3SRoger Quadros SERDES_AM654_CFG(0x0a18, 15, 8, 0x3c); 254257d0be3SRoger Quadros SERDES_AM654_CFG(0x0a38, 7, 0, 0x3e); 255257d0be3SRoger Quadros SERDES_AM654_CFG(0x0a38, 15, 8, 0x3e); 256257d0be3SRoger Quadros SERDES_AM654_CFG(0x0ae0, 7, 0, 0x07); 257257d0be3SRoger Quadros SERDES_AM654_CFG(0x0b6c, 23, 16, 0xcd); 258257d0be3SRoger Quadros SERDES_AM654_CFG(0x0b6c, 31, 24, 0x04); 259257d0be3SRoger Quadros SERDES_AM654_CFG(0x0b98, 23, 16, 0x03); 260257d0be3SRoger Quadros SERDES_AM654_CFG(0x1400, 7, 0, 0x3f); 261257d0be3SRoger Quadros SERDES_AM654_CFG(0x1404, 23, 16, 0x6f); 262257d0be3SRoger Quadros SERDES_AM654_CFG(0x1404, 31, 24, 0x6f); 263257d0be3SRoger Quadros SERDES_AM654_CFG(0x140c, 7, 0, 0x6f); 264257d0be3SRoger Quadros SERDES_AM654_CFG(0x140c, 15, 8, 0x6f); 265257d0be3SRoger Quadros SERDES_AM654_CFG(0x1410, 15, 8, 0x27); 266257d0be3SRoger Quadros SERDES_AM654_CFG(0x1414, 7, 0, 0x0c); 267257d0be3SRoger Quadros SERDES_AM654_CFG(0x1414, 23, 16, 0x07); 268257d0be3SRoger Quadros SERDES_AM654_CFG(0x1418, 23, 16, 0x40); 269257d0be3SRoger Quadros SERDES_AM654_CFG(0x141c, 7, 0, 0x00); 270257d0be3SRoger Quadros SERDES_AM654_CFG(0x141c, 15, 8, 0x1f); 271257d0be3SRoger Quadros SERDES_AM654_CFG(0x1428, 31, 24, 0x08); 272257d0be3SRoger Quadros SERDES_AM654_CFG(0x1434, 31, 24, 0x00); 273257d0be3SRoger Quadros SERDES_AM654_CFG(0x1444, 7, 0, 0x94); 274257d0be3SRoger Quadros SERDES_AM654_CFG(0x1460, 31, 24, 0x7f); 275257d0be3SRoger Quadros SERDES_AM654_CFG(0x1464, 7, 0, 0x43); 276257d0be3SRoger Quadros SERDES_AM654_CFG(0x1464, 23, 16, 0x6f); 277257d0be3SRoger Quadros SERDES_AM654_CFG(0x1464, 31, 24, 0x43); 278257d0be3SRoger Quadros SERDES_AM654_CFG(0x1484, 23, 16, 0x8f); 279257d0be3SRoger Quadros SERDES_AM654_CFG(0x1498, 7, 0, 0x4f); 280257d0be3SRoger Quadros SERDES_AM654_CFG(0x1498, 23, 16, 0x4f); 281257d0be3SRoger Quadros SERDES_AM654_CFG(0x007c, 31, 24, 0x0d); 282257d0be3SRoger Quadros SERDES_AM654_CFG(0x0b90, 15, 8, 0x0f); 283257d0be3SRoger Quadros 284257d0be3SRoger Quadros return 0; 285257d0be3SRoger Quadros } 286257d0be3SRoger Quadros 287257d0be3SRoger Quadros static int serdes_am654_pcie_init(struct serdes_am654 *phy) 288257d0be3SRoger Quadros { 28971e2f5c5SKishon Vijay Abraham I int ret; 29071e2f5c5SKishon Vijay Abraham I 29171e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->config_version, VERSION); 29271e2f5c5SKishon Vijay Abraham I if (ret) 29371e2f5c5SKishon Vijay Abraham I return ret; 29471e2f5c5SKishon Vijay Abraham I 29571e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->cmu_master_cdn_o, 0x1); 29671e2f5c5SKishon Vijay Abraham I if (ret) 29771e2f5c5SKishon Vijay Abraham I return ret; 29871e2f5c5SKishon Vijay Abraham I 29971e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->l1_master_cdn_o, 0x1); 30071e2f5c5SKishon Vijay Abraham I if (ret) 30171e2f5c5SKishon Vijay Abraham I return ret; 30271e2f5c5SKishon Vijay Abraham I 30371e2f5c5SKishon Vijay Abraham I return 0; 30471e2f5c5SKishon Vijay Abraham I } 30571e2f5c5SKishon Vijay Abraham I 306257d0be3SRoger Quadros static int serdes_am654_init(struct phy *x) 307257d0be3SRoger Quadros { 308257d0be3SRoger Quadros struct serdes_am654 *phy = phy_get_drvdata(x); 309257d0be3SRoger Quadros 310257d0be3SRoger Quadros switch (phy->type) { 311257d0be3SRoger Quadros case PHY_TYPE_PCIE: 312257d0be3SRoger Quadros return serdes_am654_pcie_init(phy); 313257d0be3SRoger Quadros case PHY_TYPE_USB3: 314257d0be3SRoger Quadros return serdes_am654_usb3_init(phy); 315257d0be3SRoger Quadros default: 316257d0be3SRoger Quadros return -EINVAL; 317257d0be3SRoger Quadros } 318257d0be3SRoger Quadros } 319257d0be3SRoger Quadros 32071e2f5c5SKishon Vijay Abraham I static int serdes_am654_reset(struct phy *x) 32171e2f5c5SKishon Vijay Abraham I { 32271e2f5c5SKishon Vijay Abraham I struct serdes_am654 *phy = phy_get_drvdata(x); 32371e2f5c5SKishon Vijay Abraham I int ret; 32471e2f5c5SKishon Vijay Abraham I 325257d0be3SRoger Quadros serdes_am654_disable_pll(phy); 326257d0be3SRoger Quadros serdes_am654_disable_txrx(phy); 327257d0be3SRoger Quadros 32871e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->por_en, 0x1); 32971e2f5c5SKishon Vijay Abraham I if (ret) 33071e2f5c5SKishon Vijay Abraham I return ret; 33171e2f5c5SKishon Vijay Abraham I 33271e2f5c5SKishon Vijay Abraham I mdelay(1); 33371e2f5c5SKishon Vijay Abraham I 33471e2f5c5SKishon Vijay Abraham I ret = regmap_field_write(phy->por_en, 0x0); 33571e2f5c5SKishon Vijay Abraham I if (ret) 33671e2f5c5SKishon Vijay Abraham I return ret; 33771e2f5c5SKishon Vijay Abraham I 33871e2f5c5SKishon Vijay Abraham I return 0; 33971e2f5c5SKishon Vijay Abraham I } 34071e2f5c5SKishon Vijay Abraham I 34171e2f5c5SKishon Vijay Abraham I static void serdes_am654_release(struct phy *x) 34271e2f5c5SKishon Vijay Abraham I { 34371e2f5c5SKishon Vijay Abraham I struct serdes_am654 *phy = phy_get_drvdata(x); 34471e2f5c5SKishon Vijay Abraham I 34571e2f5c5SKishon Vijay Abraham I phy->type = PHY_NONE; 34671e2f5c5SKishon Vijay Abraham I phy->busy = false; 34771e2f5c5SKishon Vijay Abraham I mux_control_deselect(phy->control); 34871e2f5c5SKishon Vijay Abraham I } 34971e2f5c5SKishon Vijay Abraham I 3501853bc0aSYueHaibing static struct phy *serdes_am654_xlate(struct device *dev, 3511853bc0aSYueHaibing struct of_phandle_args *args) 35271e2f5c5SKishon Vijay Abraham I { 35371e2f5c5SKishon Vijay Abraham I struct serdes_am654 *am654_phy; 35471e2f5c5SKishon Vijay Abraham I struct phy *phy; 35571e2f5c5SKishon Vijay Abraham I int ret; 35671e2f5c5SKishon Vijay Abraham I 35771e2f5c5SKishon Vijay Abraham I phy = of_phy_simple_xlate(dev, args); 35871e2f5c5SKishon Vijay Abraham I if (IS_ERR(phy)) 35971e2f5c5SKishon Vijay Abraham I return phy; 36071e2f5c5SKishon Vijay Abraham I 36171e2f5c5SKishon Vijay Abraham I am654_phy = phy_get_drvdata(phy); 36271e2f5c5SKishon Vijay Abraham I if (am654_phy->busy) 36371e2f5c5SKishon Vijay Abraham I return ERR_PTR(-EBUSY); 36471e2f5c5SKishon Vijay Abraham I 36571e2f5c5SKishon Vijay Abraham I ret = mux_control_select(am654_phy->control, args->args[1]); 36671e2f5c5SKishon Vijay Abraham I if (ret) { 36771e2f5c5SKishon Vijay Abraham I dev_err(dev, "Failed to select SERDES Lane Function\n"); 36871e2f5c5SKishon Vijay Abraham I return ERR_PTR(ret); 36971e2f5c5SKishon Vijay Abraham I } 37071e2f5c5SKishon Vijay Abraham I 37171e2f5c5SKishon Vijay Abraham I am654_phy->busy = true; 37271e2f5c5SKishon Vijay Abraham I am654_phy->type = args->args[0]; 37371e2f5c5SKishon Vijay Abraham I 37471e2f5c5SKishon Vijay Abraham I return phy; 37571e2f5c5SKishon Vijay Abraham I } 37671e2f5c5SKishon Vijay Abraham I 37771e2f5c5SKishon Vijay Abraham I static const struct phy_ops ops = { 37871e2f5c5SKishon Vijay Abraham I .reset = serdes_am654_reset, 37971e2f5c5SKishon Vijay Abraham I .init = serdes_am654_init, 38071e2f5c5SKishon Vijay Abraham I .power_on = serdes_am654_power_on, 38171e2f5c5SKishon Vijay Abraham I .power_off = serdes_am654_power_off, 38271e2f5c5SKishon Vijay Abraham I .release = serdes_am654_release, 38371e2f5c5SKishon Vijay Abraham I .owner = THIS_MODULE, 38471e2f5c5SKishon Vijay Abraham I }; 38571e2f5c5SKishon Vijay Abraham I 3867e7b8ca6SRoger Quadros #define SERDES_NUM_MUX_COMBINATIONS 16 3877e7b8ca6SRoger Quadros 3887e7b8ca6SRoger Quadros #define LICLK 0 3897e7b8ca6SRoger Quadros #define EXT_REFCLK 1 3907e7b8ca6SRoger Quadros #define RICLK 2 3917e7b8ca6SRoger Quadros 3927e7b8ca6SRoger Quadros static const int 3937e7b8ca6SRoger Quadros serdes_am654_mux_table[SERDES_NUM_MUX_COMBINATIONS][SERDES_NUM_CLOCKS] = { 3947e7b8ca6SRoger Quadros /* 3957e7b8ca6SRoger Quadros * Each combination maps to one of 3967e7b8ca6SRoger Quadros * "Figure 12-1986. SerDes Reference Clock Distribution" 3977e7b8ca6SRoger Quadros * in TRM. 3987e7b8ca6SRoger Quadros */ 3997e7b8ca6SRoger Quadros /* Parent of CMU refclk, Left output, Right output 4007e7b8ca6SRoger Quadros * either of EXT_REFCLK, LICLK, RICLK 4017e7b8ca6SRoger Quadros */ 4027e7b8ca6SRoger Quadros { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0000 */ 4037e7b8ca6SRoger Quadros { RICLK, EXT_REFCLK, EXT_REFCLK }, /* 0001 */ 4047e7b8ca6SRoger Quadros { EXT_REFCLK, RICLK, LICLK }, /* 0010 */ 4057e7b8ca6SRoger Quadros { RICLK, RICLK, EXT_REFCLK }, /* 0011 */ 4067e7b8ca6SRoger Quadros { LICLK, EXT_REFCLK, EXT_REFCLK }, /* 0100 */ 4077e7b8ca6SRoger Quadros { EXT_REFCLK, EXT_REFCLK, EXT_REFCLK }, /* 0101 */ 4087e7b8ca6SRoger Quadros { LICLK, RICLK, LICLK }, /* 0110 */ 4097e7b8ca6SRoger Quadros { EXT_REFCLK, RICLK, LICLK }, /* 0111 */ 4107e7b8ca6SRoger Quadros { EXT_REFCLK, EXT_REFCLK, LICLK }, /* 1000 */ 4117e7b8ca6SRoger Quadros { RICLK, EXT_REFCLK, LICLK }, /* 1001 */ 4127e7b8ca6SRoger Quadros { EXT_REFCLK, RICLK, EXT_REFCLK }, /* 1010 */ 4137e7b8ca6SRoger Quadros { RICLK, RICLK, EXT_REFCLK }, /* 1011 */ 4147e7b8ca6SRoger Quadros { LICLK, EXT_REFCLK, LICLK }, /* 1100 */ 4157e7b8ca6SRoger Quadros { EXT_REFCLK, EXT_REFCLK, LICLK }, /* 1101 */ 4167e7b8ca6SRoger Quadros { LICLK, RICLK, EXT_REFCLK }, /* 1110 */ 4177e7b8ca6SRoger Quadros { EXT_REFCLK, RICLK, EXT_REFCLK }, /* 1111 */ 4187e7b8ca6SRoger Quadros }; 4197e7b8ca6SRoger Quadros 42071e2f5c5SKishon Vijay Abraham I static u8 serdes_am654_clk_mux_get_parent(struct clk_hw *hw) 42171e2f5c5SKishon Vijay Abraham I { 42271e2f5c5SKishon Vijay Abraham I struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw); 42371e2f5c5SKishon Vijay Abraham I struct regmap *regmap = mux->regmap; 42471e2f5c5SKishon Vijay Abraham I unsigned int reg = mux->reg; 42571e2f5c5SKishon Vijay Abraham I unsigned int val; 42671e2f5c5SKishon Vijay Abraham I 42771e2f5c5SKishon Vijay Abraham I regmap_read(regmap, reg, &val); 4287e7b8ca6SRoger Quadros val &= AM654_SERDES_CTRL_CLKSEL_MASK; 4297e7b8ca6SRoger Quadros val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT; 43071e2f5c5SKishon Vijay Abraham I 4317e7b8ca6SRoger Quadros return serdes_am654_mux_table[val][mux->clk_id]; 43271e2f5c5SKishon Vijay Abraham I } 43371e2f5c5SKishon Vijay Abraham I 43471e2f5c5SKishon Vijay Abraham I static int serdes_am654_clk_mux_set_parent(struct clk_hw *hw, u8 index) 43571e2f5c5SKishon Vijay Abraham I { 43671e2f5c5SKishon Vijay Abraham I struct serdes_am654_clk_mux *mux = to_serdes_am654_clk_mux(hw); 43771e2f5c5SKishon Vijay Abraham I struct regmap *regmap = mux->regmap; 438bd0e79f1SStephen Boyd const char *name = clk_hw_get_name(hw); 43971e2f5c5SKishon Vijay Abraham I unsigned int reg = mux->reg; 4407e7b8ca6SRoger Quadros int clk_id = mux->clk_id; 4417e7b8ca6SRoger Quadros int parents[SERDES_NUM_CLOCKS]; 4427e7b8ca6SRoger Quadros const int *p; 4437e7b8ca6SRoger Quadros u32 val; 4447e7b8ca6SRoger Quadros int found, i; 44571e2f5c5SKishon Vijay Abraham I int ret; 44671e2f5c5SKishon Vijay Abraham I 4477e7b8ca6SRoger Quadros /* get existing setting */ 4487e7b8ca6SRoger Quadros regmap_read(regmap, reg, &val); 4497e7b8ca6SRoger Quadros val &= AM654_SERDES_CTRL_CLKSEL_MASK; 4507e7b8ca6SRoger Quadros val >>= AM654_SERDES_CTRL_CLKSEL_SHIFT; 45171e2f5c5SKishon Vijay Abraham I 4527e7b8ca6SRoger Quadros for (i = 0; i < SERDES_NUM_CLOCKS; i++) 4537e7b8ca6SRoger Quadros parents[i] = serdes_am654_mux_table[val][i]; 4547e7b8ca6SRoger Quadros 4557e7b8ca6SRoger Quadros /* change parent of this clock. others left intact */ 4567e7b8ca6SRoger Quadros parents[clk_id] = index; 4577e7b8ca6SRoger Quadros 4587e7b8ca6SRoger Quadros /* Find the match */ 4597e7b8ca6SRoger Quadros for (val = 0; val < SERDES_NUM_MUX_COMBINATIONS; val++) { 4607e7b8ca6SRoger Quadros p = serdes_am654_mux_table[val]; 4617e7b8ca6SRoger Quadros found = 1; 4627e7b8ca6SRoger Quadros for (i = 0; i < SERDES_NUM_CLOCKS; i++) { 4637e7b8ca6SRoger Quadros if (parents[i] != p[i]) { 4647e7b8ca6SRoger Quadros found = 0; 4657e7b8ca6SRoger Quadros break; 4667e7b8ca6SRoger Quadros } 4677e7b8ca6SRoger Quadros } 4687e7b8ca6SRoger Quadros 4697e7b8ca6SRoger Quadros if (found) 4707e7b8ca6SRoger Quadros break; 4717e7b8ca6SRoger Quadros } 4727e7b8ca6SRoger Quadros 4737e7b8ca6SRoger Quadros if (!found) { 4747e7b8ca6SRoger Quadros /* 4757e7b8ca6SRoger Quadros * This can never happen, unless we missed 4767e7b8ca6SRoger Quadros * a valid combination in serdes_am654_mux_table. 4777e7b8ca6SRoger Quadros */ 478bd0e79f1SStephen Boyd WARN(1, "Failed to find the parent of %s clock\n", name); 47971e2f5c5SKishon Vijay Abraham I return -EINVAL; 4807e7b8ca6SRoger Quadros } 48171e2f5c5SKishon Vijay Abraham I 4827e7b8ca6SRoger Quadros val <<= AM654_SERDES_CTRL_CLKSEL_SHIFT; 4837e7b8ca6SRoger Quadros ret = regmap_update_bits(regmap, reg, AM654_SERDES_CTRL_CLKSEL_MASK, 4847e7b8ca6SRoger Quadros val); 48571e2f5c5SKishon Vijay Abraham I 48671e2f5c5SKishon Vijay Abraham I return ret; 48771e2f5c5SKishon Vijay Abraham I } 48871e2f5c5SKishon Vijay Abraham I 48971e2f5c5SKishon Vijay Abraham I static const struct clk_ops serdes_am654_clk_mux_ops = { 49071e2f5c5SKishon Vijay Abraham I .set_parent = serdes_am654_clk_mux_set_parent, 49171e2f5c5SKishon Vijay Abraham I .get_parent = serdes_am654_clk_mux_get_parent, 49271e2f5c5SKishon Vijay Abraham I }; 49371e2f5c5SKishon Vijay Abraham I 49471e2f5c5SKishon Vijay Abraham I static int serdes_am654_clk_register(struct serdes_am654 *am654_phy, 49571e2f5c5SKishon Vijay Abraham I const char *clock_name, int clock_num) 49671e2f5c5SKishon Vijay Abraham I { 49771e2f5c5SKishon Vijay Abraham I struct device_node *node = am654_phy->of_node; 49871e2f5c5SKishon Vijay Abraham I struct device *dev = am654_phy->dev; 49971e2f5c5SKishon Vijay Abraham I struct serdes_am654_clk_mux *mux; 50071e2f5c5SKishon Vijay Abraham I struct device_node *regmap_node; 50171e2f5c5SKishon Vijay Abraham I const char **parent_names; 50271e2f5c5SKishon Vijay Abraham I struct clk_init_data *init; 50371e2f5c5SKishon Vijay Abraham I unsigned int num_parents; 50471e2f5c5SKishon Vijay Abraham I struct regmap *regmap; 50571e2f5c5SKishon Vijay Abraham I const __be32 *addr; 50671e2f5c5SKishon Vijay Abraham I unsigned int reg; 50771e2f5c5SKishon Vijay Abraham I struct clk *clk; 5083e644828SWen Yang int ret = 0; 50971e2f5c5SKishon Vijay Abraham I 51071e2f5c5SKishon Vijay Abraham I mux = devm_kzalloc(dev, sizeof(*mux), GFP_KERNEL); 51171e2f5c5SKishon Vijay Abraham I if (!mux) 51271e2f5c5SKishon Vijay Abraham I return -ENOMEM; 51371e2f5c5SKishon Vijay Abraham I 51471e2f5c5SKishon Vijay Abraham I init = &mux->clk_data; 51571e2f5c5SKishon Vijay Abraham I 51671e2f5c5SKishon Vijay Abraham I regmap_node = of_parse_phandle(node, "ti,serdes-clk", 0); 51771e2f5c5SKishon Vijay Abraham I if (!regmap_node) { 51871e2f5c5SKishon Vijay Abraham I dev_err(dev, "Fail to get serdes-clk node\n"); 5193e644828SWen Yang ret = -ENODEV; 5203e644828SWen Yang goto out_put_node; 52171e2f5c5SKishon Vijay Abraham I } 52271e2f5c5SKishon Vijay Abraham I 52371e2f5c5SKishon Vijay Abraham I regmap = syscon_node_to_regmap(regmap_node->parent); 52471e2f5c5SKishon Vijay Abraham I if (IS_ERR(regmap)) { 52571e2f5c5SKishon Vijay Abraham I dev_err(dev, "Fail to get Syscon regmap\n"); 5263e644828SWen Yang ret = PTR_ERR(regmap); 5273e644828SWen Yang goto out_put_node; 52871e2f5c5SKishon Vijay Abraham I } 52971e2f5c5SKishon Vijay Abraham I 53071e2f5c5SKishon Vijay Abraham I num_parents = of_clk_get_parent_count(node); 53171e2f5c5SKishon Vijay Abraham I if (num_parents < 2) { 53271e2f5c5SKishon Vijay Abraham I dev_err(dev, "SERDES clock must have parents\n"); 5333e644828SWen Yang ret = -EINVAL; 5343e644828SWen Yang goto out_put_node; 53571e2f5c5SKishon Vijay Abraham I } 53671e2f5c5SKishon Vijay Abraham I 53771e2f5c5SKishon Vijay Abraham I parent_names = devm_kzalloc(dev, (sizeof(char *) * num_parents), 53871e2f5c5SKishon Vijay Abraham I GFP_KERNEL); 5393e644828SWen Yang if (!parent_names) { 5403e644828SWen Yang ret = -ENOMEM; 5413e644828SWen Yang goto out_put_node; 5423e644828SWen Yang } 54371e2f5c5SKishon Vijay Abraham I 54471e2f5c5SKishon Vijay Abraham I of_clk_parent_fill(node, parent_names, num_parents); 54571e2f5c5SKishon Vijay Abraham I 54671e2f5c5SKishon Vijay Abraham I addr = of_get_address(regmap_node, 0, NULL, NULL); 5473e644828SWen Yang if (!addr) { 5483e644828SWen Yang ret = -EINVAL; 5493e644828SWen Yang goto out_put_node; 5503e644828SWen Yang } 55171e2f5c5SKishon Vijay Abraham I 55271e2f5c5SKishon Vijay Abraham I reg = be32_to_cpu(*addr); 55371e2f5c5SKishon Vijay Abraham I 55471e2f5c5SKishon Vijay Abraham I init->ops = &serdes_am654_clk_mux_ops; 55571e2f5c5SKishon Vijay Abraham I init->flags = CLK_SET_RATE_NO_REPARENT; 55671e2f5c5SKishon Vijay Abraham I init->parent_names = parent_names; 55771e2f5c5SKishon Vijay Abraham I init->num_parents = num_parents; 55871e2f5c5SKishon Vijay Abraham I init->name = clock_name; 55971e2f5c5SKishon Vijay Abraham I 56071e2f5c5SKishon Vijay Abraham I mux->regmap = regmap; 56171e2f5c5SKishon Vijay Abraham I mux->reg = reg; 5627e7b8ca6SRoger Quadros mux->clk_id = clock_num; 56371e2f5c5SKishon Vijay Abraham I mux->hw.init = init; 56471e2f5c5SKishon Vijay Abraham I 56571e2f5c5SKishon Vijay Abraham I clk = devm_clk_register(dev, &mux->hw); 5663e644828SWen Yang if (IS_ERR(clk)) { 5673e644828SWen Yang ret = PTR_ERR(clk); 5683e644828SWen Yang goto out_put_node; 5693e644828SWen Yang } 57071e2f5c5SKishon Vijay Abraham I 57171e2f5c5SKishon Vijay Abraham I am654_phy->clks[clock_num] = clk; 57271e2f5c5SKishon Vijay Abraham I 5733e644828SWen Yang out_put_node: 5743e644828SWen Yang of_node_put(regmap_node); 5753e644828SWen Yang return ret; 57671e2f5c5SKishon Vijay Abraham I } 57771e2f5c5SKishon Vijay Abraham I 57871e2f5c5SKishon Vijay Abraham I static const struct of_device_id serdes_am654_id_table[] = { 57971e2f5c5SKishon Vijay Abraham I { 58071e2f5c5SKishon Vijay Abraham I .compatible = "ti,phy-am654-serdes", 58171e2f5c5SKishon Vijay Abraham I }, 58271e2f5c5SKishon Vijay Abraham I {} 58371e2f5c5SKishon Vijay Abraham I }; 58471e2f5c5SKishon Vijay Abraham I MODULE_DEVICE_TABLE(of, serdes_am654_id_table); 58571e2f5c5SKishon Vijay Abraham I 58671e2f5c5SKishon Vijay Abraham I static int serdes_am654_regfield_init(struct serdes_am654 *am654_phy) 58771e2f5c5SKishon Vijay Abraham I { 58871e2f5c5SKishon Vijay Abraham I struct regmap *regmap = am654_phy->regmap; 58971e2f5c5SKishon Vijay Abraham I struct device *dev = am654_phy->dev; 59071e2f5c5SKishon Vijay Abraham I 59171e2f5c5SKishon Vijay Abraham I am654_phy->cmu_master_cdn_o = devm_regmap_field_alloc(dev, regmap, 59271e2f5c5SKishon Vijay Abraham I cmu_master_cdn_o); 59371e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->cmu_master_cdn_o)) { 59471e2f5c5SKishon Vijay Abraham I dev_err(dev, "CMU_MASTER_CDN_O reg field init failed\n"); 59571e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->cmu_master_cdn_o); 59671e2f5c5SKishon Vijay Abraham I } 59771e2f5c5SKishon Vijay Abraham I 59871e2f5c5SKishon Vijay Abraham I am654_phy->config_version = devm_regmap_field_alloc(dev, regmap, 59971e2f5c5SKishon Vijay Abraham I config_version); 60071e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->config_version)) { 60171e2f5c5SKishon Vijay Abraham I dev_err(dev, "CONFIG_VERSION reg field init failed\n"); 60271e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->config_version); 60371e2f5c5SKishon Vijay Abraham I } 60471e2f5c5SKishon Vijay Abraham I 60571e2f5c5SKishon Vijay Abraham I am654_phy->l1_master_cdn_o = devm_regmap_field_alloc(dev, regmap, 60671e2f5c5SKishon Vijay Abraham I l1_master_cdn_o); 60771e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->l1_master_cdn_o)) { 60871e2f5c5SKishon Vijay Abraham I dev_err(dev, "L1_MASTER_CDN_O reg field init failed\n"); 60971e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->l1_master_cdn_o); 61071e2f5c5SKishon Vijay Abraham I } 61171e2f5c5SKishon Vijay Abraham I 61271e2f5c5SKishon Vijay Abraham I am654_phy->cmu_ok_i_0 = devm_regmap_field_alloc(dev, regmap, 61371e2f5c5SKishon Vijay Abraham I cmu_ok_i_0); 61471e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->cmu_ok_i_0)) { 61571e2f5c5SKishon Vijay Abraham I dev_err(dev, "CMU_OK_I_0 reg field init failed\n"); 61671e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->cmu_ok_i_0); 61771e2f5c5SKishon Vijay Abraham I } 61871e2f5c5SKishon Vijay Abraham I 61971e2f5c5SKishon Vijay Abraham I am654_phy->por_en = devm_regmap_field_alloc(dev, regmap, por_en); 62071e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->por_en)) { 62171e2f5c5SKishon Vijay Abraham I dev_err(dev, "POR_EN reg field init failed\n"); 62271e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->por_en); 62371e2f5c5SKishon Vijay Abraham I } 62471e2f5c5SKishon Vijay Abraham I 62571e2f5c5SKishon Vijay Abraham I am654_phy->tx0_enable = devm_regmap_field_alloc(dev, regmap, 62671e2f5c5SKishon Vijay Abraham I tx0_enable); 62771e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->tx0_enable)) { 62871e2f5c5SKishon Vijay Abraham I dev_err(dev, "TX0_ENABLE reg field init failed\n"); 62971e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->tx0_enable); 63071e2f5c5SKishon Vijay Abraham I } 63171e2f5c5SKishon Vijay Abraham I 63271e2f5c5SKishon Vijay Abraham I am654_phy->rx0_enable = devm_regmap_field_alloc(dev, regmap, 63371e2f5c5SKishon Vijay Abraham I rx0_enable); 63471e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->rx0_enable)) { 63571e2f5c5SKishon Vijay Abraham I dev_err(dev, "RX0_ENABLE reg field init failed\n"); 63671e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->rx0_enable); 63771e2f5c5SKishon Vijay Abraham I } 63871e2f5c5SKishon Vijay Abraham I 63971e2f5c5SKishon Vijay Abraham I am654_phy->pll_enable = devm_regmap_field_alloc(dev, regmap, 64071e2f5c5SKishon Vijay Abraham I pll_enable); 64171e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->pll_enable)) { 64271e2f5c5SKishon Vijay Abraham I dev_err(dev, "PLL_ENABLE reg field init failed\n"); 64371e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->pll_enable); 64471e2f5c5SKishon Vijay Abraham I } 64571e2f5c5SKishon Vijay Abraham I 64671e2f5c5SKishon Vijay Abraham I am654_phy->pll_ok = devm_regmap_field_alloc(dev, regmap, pll_ok); 64771e2f5c5SKishon Vijay Abraham I if (IS_ERR(am654_phy->pll_ok)) { 64871e2f5c5SKishon Vijay Abraham I dev_err(dev, "PLL_OK reg field init failed\n"); 64971e2f5c5SKishon Vijay Abraham I return PTR_ERR(am654_phy->pll_ok); 65071e2f5c5SKishon Vijay Abraham I } 65171e2f5c5SKishon Vijay Abraham I 65271e2f5c5SKishon Vijay Abraham I return 0; 65371e2f5c5SKishon Vijay Abraham I } 65471e2f5c5SKishon Vijay Abraham I 65571e2f5c5SKishon Vijay Abraham I static int serdes_am654_probe(struct platform_device *pdev) 65671e2f5c5SKishon Vijay Abraham I { 65771e2f5c5SKishon Vijay Abraham I struct phy_provider *phy_provider; 65871e2f5c5SKishon Vijay Abraham I struct device *dev = &pdev->dev; 65971e2f5c5SKishon Vijay Abraham I struct device_node *node = dev->of_node; 66071e2f5c5SKishon Vijay Abraham I struct clk_onecell_data *clk_data; 66171e2f5c5SKishon Vijay Abraham I struct serdes_am654 *am654_phy; 66271e2f5c5SKishon Vijay Abraham I struct mux_control *control; 66371e2f5c5SKishon Vijay Abraham I const char *clock_name; 66471e2f5c5SKishon Vijay Abraham I struct regmap *regmap; 66571e2f5c5SKishon Vijay Abraham I void __iomem *base; 66671e2f5c5SKishon Vijay Abraham I struct phy *phy; 66771e2f5c5SKishon Vijay Abraham I int ret; 66871e2f5c5SKishon Vijay Abraham I int i; 66971e2f5c5SKishon Vijay Abraham I 67071e2f5c5SKishon Vijay Abraham I am654_phy = devm_kzalloc(dev, sizeof(*am654_phy), GFP_KERNEL); 67171e2f5c5SKishon Vijay Abraham I if (!am654_phy) 67271e2f5c5SKishon Vijay Abraham I return -ENOMEM; 67371e2f5c5SKishon Vijay Abraham I 67471e2f5c5SKishon Vijay Abraham I base = devm_platform_ioremap_resource(pdev, 0); 67571e2f5c5SKishon Vijay Abraham I if (IS_ERR(base)) 67671e2f5c5SKishon Vijay Abraham I return PTR_ERR(base); 67771e2f5c5SKishon Vijay Abraham I 67871e2f5c5SKishon Vijay Abraham I regmap = devm_regmap_init_mmio(dev, base, &serdes_am654_regmap_config); 67971e2f5c5SKishon Vijay Abraham I if (IS_ERR(regmap)) { 68071e2f5c5SKishon Vijay Abraham I dev_err(dev, "Failed to initialize regmap\n"); 68171e2f5c5SKishon Vijay Abraham I return PTR_ERR(regmap); 68271e2f5c5SKishon Vijay Abraham I } 68371e2f5c5SKishon Vijay Abraham I 68471e2f5c5SKishon Vijay Abraham I control = devm_mux_control_get(dev, NULL); 68571e2f5c5SKishon Vijay Abraham I if (IS_ERR(control)) 68671e2f5c5SKishon Vijay Abraham I return PTR_ERR(control); 68771e2f5c5SKishon Vijay Abraham I 68871e2f5c5SKishon Vijay Abraham I am654_phy->dev = dev; 68971e2f5c5SKishon Vijay Abraham I am654_phy->of_node = node; 69071e2f5c5SKishon Vijay Abraham I am654_phy->regmap = regmap; 69171e2f5c5SKishon Vijay Abraham I am654_phy->control = control; 69271e2f5c5SKishon Vijay Abraham I am654_phy->type = PHY_NONE; 69371e2f5c5SKishon Vijay Abraham I 69471e2f5c5SKishon Vijay Abraham I ret = serdes_am654_regfield_init(am654_phy); 69571e2f5c5SKishon Vijay Abraham I if (ret) { 69671e2f5c5SKishon Vijay Abraham I dev_err(dev, "Failed to initialize regfields\n"); 69771e2f5c5SKishon Vijay Abraham I return ret; 69871e2f5c5SKishon Vijay Abraham I } 69971e2f5c5SKishon Vijay Abraham I 70071e2f5c5SKishon Vijay Abraham I platform_set_drvdata(pdev, am654_phy); 70171e2f5c5SKishon Vijay Abraham I 70271e2f5c5SKishon Vijay Abraham I for (i = 0; i < SERDES_NUM_CLOCKS; i++) { 70371e2f5c5SKishon Vijay Abraham I ret = of_property_read_string_index(node, "clock-output-names", 70471e2f5c5SKishon Vijay Abraham I i, &clock_name); 70571e2f5c5SKishon Vijay Abraham I if (ret) { 70671e2f5c5SKishon Vijay Abraham I dev_err(dev, "Failed to get clock name\n"); 70771e2f5c5SKishon Vijay Abraham I return ret; 70871e2f5c5SKishon Vijay Abraham I } 70971e2f5c5SKishon Vijay Abraham I 71071e2f5c5SKishon Vijay Abraham I ret = serdes_am654_clk_register(am654_phy, clock_name, i); 71171e2f5c5SKishon Vijay Abraham I if (ret) { 71271e2f5c5SKishon Vijay Abraham I dev_err(dev, "Failed to initialize clock %s\n", 71371e2f5c5SKishon Vijay Abraham I clock_name); 71471e2f5c5SKishon Vijay Abraham I return ret; 71571e2f5c5SKishon Vijay Abraham I } 71671e2f5c5SKishon Vijay Abraham I } 71771e2f5c5SKishon Vijay Abraham I 71871e2f5c5SKishon Vijay Abraham I clk_data = &am654_phy->clk_data; 71971e2f5c5SKishon Vijay Abraham I clk_data->clks = am654_phy->clks; 72071e2f5c5SKishon Vijay Abraham I clk_data->clk_num = SERDES_NUM_CLOCKS; 72171e2f5c5SKishon Vijay Abraham I ret = of_clk_add_provider(node, of_clk_src_onecell_get, clk_data); 72271e2f5c5SKishon Vijay Abraham I if (ret) 72371e2f5c5SKishon Vijay Abraham I return ret; 72471e2f5c5SKishon Vijay Abraham I 72571e2f5c5SKishon Vijay Abraham I pm_runtime_enable(dev); 72671e2f5c5SKishon Vijay Abraham I 72771e2f5c5SKishon Vijay Abraham I phy = devm_phy_create(dev, NULL, &ops); 72871e2f5c5SKishon Vijay Abraham I if (IS_ERR(phy)) 72971e2f5c5SKishon Vijay Abraham I return PTR_ERR(phy); 73071e2f5c5SKishon Vijay Abraham I 73171e2f5c5SKishon Vijay Abraham I phy_set_drvdata(phy, am654_phy); 73271e2f5c5SKishon Vijay Abraham I phy_provider = devm_of_phy_provider_register(dev, serdes_am654_xlate); 73371e2f5c5SKishon Vijay Abraham I if (IS_ERR(phy_provider)) { 73471e2f5c5SKishon Vijay Abraham I ret = PTR_ERR(phy_provider); 73571e2f5c5SKishon Vijay Abraham I goto clk_err; 73671e2f5c5SKishon Vijay Abraham I } 73771e2f5c5SKishon Vijay Abraham I 73871e2f5c5SKishon Vijay Abraham I return 0; 73971e2f5c5SKishon Vijay Abraham I 74071e2f5c5SKishon Vijay Abraham I clk_err: 74171e2f5c5SKishon Vijay Abraham I of_clk_del_provider(node); 74271e2f5c5SKishon Vijay Abraham I 74371e2f5c5SKishon Vijay Abraham I return ret; 74471e2f5c5SKishon Vijay Abraham I } 74571e2f5c5SKishon Vijay Abraham I 74671e2f5c5SKishon Vijay Abraham I static int serdes_am654_remove(struct platform_device *pdev) 74771e2f5c5SKishon Vijay Abraham I { 74871e2f5c5SKishon Vijay Abraham I struct serdes_am654 *am654_phy = platform_get_drvdata(pdev); 74971e2f5c5SKishon Vijay Abraham I struct device_node *node = am654_phy->of_node; 75071e2f5c5SKishon Vijay Abraham I 75171e2f5c5SKishon Vijay Abraham I pm_runtime_disable(&pdev->dev); 75271e2f5c5SKishon Vijay Abraham I of_clk_del_provider(node); 75371e2f5c5SKishon Vijay Abraham I 75471e2f5c5SKishon Vijay Abraham I return 0; 75571e2f5c5SKishon Vijay Abraham I } 75671e2f5c5SKishon Vijay Abraham I 75771e2f5c5SKishon Vijay Abraham I static struct platform_driver serdes_am654_driver = { 75871e2f5c5SKishon Vijay Abraham I .probe = serdes_am654_probe, 75971e2f5c5SKishon Vijay Abraham I .remove = serdes_am654_remove, 76071e2f5c5SKishon Vijay Abraham I .driver = { 76171e2f5c5SKishon Vijay Abraham I .name = "phy-am654", 76271e2f5c5SKishon Vijay Abraham I .of_match_table = serdes_am654_id_table, 76371e2f5c5SKishon Vijay Abraham I }, 76471e2f5c5SKishon Vijay Abraham I }; 76571e2f5c5SKishon Vijay Abraham I module_platform_driver(serdes_am654_driver); 76671e2f5c5SKishon Vijay Abraham I 76771e2f5c5SKishon Vijay Abraham I MODULE_AUTHOR("Texas Instruments Inc."); 76871e2f5c5SKishon Vijay Abraham I MODULE_DESCRIPTION("TI AM654x SERDES driver"); 76971e2f5c5SKishon Vijay Abraham I MODULE_LICENSE("GPL v2"); 770