18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2018 Rockchip Electronics Co. Ltd. 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Author: Wyon Bi <bivvy.bi@rock-chips.com> 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <linux/kernel.h> 98c2ecf20Sopenharmony_ci#include <linux/clk.h> 108c2ecf20Sopenharmony_ci#include <linux/iopoll.h> 118c2ecf20Sopenharmony_ci#include <linux/clk-provider.h> 128c2ecf20Sopenharmony_ci#include <linux/delay.h> 138c2ecf20Sopenharmony_ci#include <linux/init.h> 148c2ecf20Sopenharmony_ci#include <linux/module.h> 158c2ecf20Sopenharmony_ci#include <linux/of_device.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/reset.h> 188c2ecf20Sopenharmony_ci#include <linux/phy/phy.h> 198c2ecf20Sopenharmony_ci#include <linux/phy/phy-mipi-dphy.h> 208c2ecf20Sopenharmony_ci#include <linux/pm_runtime.h> 218c2ecf20Sopenharmony_ci#include <linux/mfd/syscon.h> 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define PSEC_PER_SEC 1000000000000LL 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ci#define UPDATE(x, h, l) (((x) << (l)) & GENMASK((h), (l))) 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci/* 288c2ecf20Sopenharmony_ci * The offset address[7:0] is distributed two parts, one from the bit7 to bit5 298c2ecf20Sopenharmony_ci * is the first address, the other from the bit4 to bit0 is the second address. 308c2ecf20Sopenharmony_ci * when you configure the registers, you must set both of them. The Clock Lane 318c2ecf20Sopenharmony_ci * and Data Lane use the same registers with the same second address, but the 328c2ecf20Sopenharmony_ci * first address is different. 338c2ecf20Sopenharmony_ci */ 348c2ecf20Sopenharmony_ci#define FIRST_ADDRESS(x) (((x) & 0x7) << 5) 358c2ecf20Sopenharmony_ci#define SECOND_ADDRESS(x) (((x) & 0x1f) << 0) 368c2ecf20Sopenharmony_ci#define PHY_REG(first, second) (FIRST_ADDRESS(first) | \ 378c2ecf20Sopenharmony_ci SECOND_ADDRESS(second)) 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci/* Analog Register Part: reg00 */ 408c2ecf20Sopenharmony_ci#define BANDGAP_POWER_MASK BIT(7) 418c2ecf20Sopenharmony_ci#define BANDGAP_POWER_DOWN BIT(7) 428c2ecf20Sopenharmony_ci#define BANDGAP_POWER_ON 0 438c2ecf20Sopenharmony_ci#define LANE_EN_MASK GENMASK(6, 2) 448c2ecf20Sopenharmony_ci#define LANE_EN_CK BIT(6) 458c2ecf20Sopenharmony_ci#define LANE_EN_3 BIT(5) 468c2ecf20Sopenharmony_ci#define LANE_EN_2 BIT(4) 478c2ecf20Sopenharmony_ci#define LANE_EN_1 BIT(3) 488c2ecf20Sopenharmony_ci#define LANE_EN_0 BIT(2) 498c2ecf20Sopenharmony_ci#define POWER_WORK_MASK GENMASK(1, 0) 508c2ecf20Sopenharmony_ci#define POWER_WORK_ENABLE UPDATE(1, 1, 0) 518c2ecf20Sopenharmony_ci#define POWER_WORK_DISABLE UPDATE(2, 1, 0) 528c2ecf20Sopenharmony_ci/* Analog Register Part: reg01 */ 538c2ecf20Sopenharmony_ci#define REG_SYNCRST_MASK BIT(2) 548c2ecf20Sopenharmony_ci#define REG_SYNCRST_RESET BIT(2) 558c2ecf20Sopenharmony_ci#define REG_SYNCRST_NORMAL 0 568c2ecf20Sopenharmony_ci#define REG_LDOPD_MASK BIT(1) 578c2ecf20Sopenharmony_ci#define REG_LDOPD_POWER_DOWN BIT(1) 588c2ecf20Sopenharmony_ci#define REG_LDOPD_POWER_ON 0 598c2ecf20Sopenharmony_ci#define REG_PLLPD_MASK BIT(0) 608c2ecf20Sopenharmony_ci#define REG_PLLPD_POWER_DOWN BIT(0) 618c2ecf20Sopenharmony_ci#define REG_PLLPD_POWER_ON 0 628c2ecf20Sopenharmony_ci/* Analog Register Part: reg03 */ 638c2ecf20Sopenharmony_ci#define REG_FBDIV_HI_MASK BIT(5) 648c2ecf20Sopenharmony_ci#define REG_FBDIV_HI(x) UPDATE((x >> 8), 5, 5) 658c2ecf20Sopenharmony_ci#define REG_PREDIV_MASK GENMASK(4, 0) 668c2ecf20Sopenharmony_ci#define REG_PREDIV(x) UPDATE(x, 4, 0) 678c2ecf20Sopenharmony_ci/* Analog Register Part: reg04 */ 688c2ecf20Sopenharmony_ci#define REG_FBDIV_LO_MASK GENMASK(7, 0) 698c2ecf20Sopenharmony_ci#define REG_FBDIV_LO(x) UPDATE(x, 7, 0) 708c2ecf20Sopenharmony_ci/* Analog Register Part: reg05 */ 718c2ecf20Sopenharmony_ci#define SAMPLE_CLOCK_PHASE_MASK GENMASK(6, 4) 728c2ecf20Sopenharmony_ci#define SAMPLE_CLOCK_PHASE(x) UPDATE(x, 6, 4) 738c2ecf20Sopenharmony_ci#define CLOCK_LANE_SKEW_PHASE_MASK GENMASK(2, 0) 748c2ecf20Sopenharmony_ci#define CLOCK_LANE_SKEW_PHASE(x) UPDATE(x, 2, 0) 758c2ecf20Sopenharmony_ci/* Analog Register Part: reg06 */ 768c2ecf20Sopenharmony_ci#define DATA_LANE_3_SKEW_PHASE_MASK GENMASK(6, 4) 778c2ecf20Sopenharmony_ci#define DATA_LANE_3_SKEW_PHASE(x) UPDATE(x, 6, 4) 788c2ecf20Sopenharmony_ci#define DATA_LANE_2_SKEW_PHASE_MASK GENMASK(2, 0) 798c2ecf20Sopenharmony_ci#define DATA_LANE_2_SKEW_PHASE(x) UPDATE(x, 2, 0) 808c2ecf20Sopenharmony_ci/* Analog Register Part: reg07 */ 818c2ecf20Sopenharmony_ci#define DATA_LANE_1_SKEW_PHASE_MASK GENMASK(6, 4) 828c2ecf20Sopenharmony_ci#define DATA_LANE_1_SKEW_PHASE(x) UPDATE(x, 6, 4) 838c2ecf20Sopenharmony_ci#define DATA_LANE_0_SKEW_PHASE_MASK GENMASK(2, 0) 848c2ecf20Sopenharmony_ci#define DATA_LANE_0_SKEW_PHASE(x) UPDATE(x, 2, 0) 858c2ecf20Sopenharmony_ci/* Analog Register Part: reg08 */ 868c2ecf20Sopenharmony_ci#define SAMPLE_CLOCK_DIRECTION_MASK BIT(4) 878c2ecf20Sopenharmony_ci#define SAMPLE_CLOCK_DIRECTION_REVERSE BIT(4) 888c2ecf20Sopenharmony_ci#define SAMPLE_CLOCK_DIRECTION_FORWARD 0 898c2ecf20Sopenharmony_ci/* Digital Register Part: reg00 */ 908c2ecf20Sopenharmony_ci#define REG_DIG_RSTN_MASK BIT(0) 918c2ecf20Sopenharmony_ci#define REG_DIG_RSTN_NORMAL BIT(0) 928c2ecf20Sopenharmony_ci#define REG_DIG_RSTN_RESET 0 938c2ecf20Sopenharmony_ci/* Digital Register Part: reg01 */ 948c2ecf20Sopenharmony_ci#define INVERT_TXCLKESC_MASK BIT(1) 958c2ecf20Sopenharmony_ci#define INVERT_TXCLKESC_ENABLE BIT(1) 968c2ecf20Sopenharmony_ci#define INVERT_TXCLKESC_DISABLE 0 978c2ecf20Sopenharmony_ci#define INVERT_TXBYTECLKHS_MASK BIT(0) 988c2ecf20Sopenharmony_ci#define INVERT_TXBYTECLKHS_ENABLE BIT(0) 998c2ecf20Sopenharmony_ci#define INVERT_TXBYTECLKHS_DISABLE 0 1008c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg05 */ 1018c2ecf20Sopenharmony_ci#define T_LPX_CNT_MASK GENMASK(5, 0) 1028c2ecf20Sopenharmony_ci#define T_LPX_CNT(x) UPDATE(x, 5, 0) 1038c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg06 */ 1048c2ecf20Sopenharmony_ci#define T_HS_PREPARE_CNT_MASK GENMASK(6, 0) 1058c2ecf20Sopenharmony_ci#define T_HS_PREPARE_CNT(x) UPDATE(x, 6, 0) 1068c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg07 */ 1078c2ecf20Sopenharmony_ci#define T_HS_ZERO_CNT_MASK GENMASK(5, 0) 1088c2ecf20Sopenharmony_ci#define T_HS_ZERO_CNT(x) UPDATE(x, 5, 0) 1098c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg08 */ 1108c2ecf20Sopenharmony_ci#define T_HS_TRAIL_CNT_MASK GENMASK(6, 0) 1118c2ecf20Sopenharmony_ci#define T_HS_TRAIL_CNT(x) UPDATE(x, 6, 0) 1128c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg09 */ 1138c2ecf20Sopenharmony_ci#define T_HS_EXIT_CNT_MASK GENMASK(4, 0) 1148c2ecf20Sopenharmony_ci#define T_HS_EXIT_CNT(x) UPDATE(x, 4, 0) 1158c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg0a */ 1168c2ecf20Sopenharmony_ci#define T_CLK_POST_CNT_MASK GENMASK(3, 0) 1178c2ecf20Sopenharmony_ci#define T_CLK_POST_CNT(x) UPDATE(x, 3, 0) 1188c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg0c */ 1198c2ecf20Sopenharmony_ci#define LPDT_TX_PPI_SYNC_MASK BIT(2) 1208c2ecf20Sopenharmony_ci#define LPDT_TX_PPI_SYNC_ENABLE BIT(2) 1218c2ecf20Sopenharmony_ci#define LPDT_TX_PPI_SYNC_DISABLE 0 1228c2ecf20Sopenharmony_ci#define T_WAKEUP_CNT_HI_MASK GENMASK(1, 0) 1238c2ecf20Sopenharmony_ci#define T_WAKEUP_CNT_HI(x) UPDATE(x, 1, 0) 1248c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg0d */ 1258c2ecf20Sopenharmony_ci#define T_WAKEUP_CNT_LO_MASK GENMASK(7, 0) 1268c2ecf20Sopenharmony_ci#define T_WAKEUP_CNT_LO(x) UPDATE(x, 7, 0) 1278c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg0e */ 1288c2ecf20Sopenharmony_ci#define T_CLK_PRE_CNT_MASK GENMASK(3, 0) 1298c2ecf20Sopenharmony_ci#define T_CLK_PRE_CNT(x) UPDATE(x, 3, 0) 1308c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg10 */ 1318c2ecf20Sopenharmony_ci#define T_TA_GO_CNT_MASK GENMASK(5, 0) 1328c2ecf20Sopenharmony_ci#define T_TA_GO_CNT(x) UPDATE(x, 5, 0) 1338c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg11 */ 1348c2ecf20Sopenharmony_ci#define T_TA_SURE_CNT_MASK GENMASK(5, 0) 1358c2ecf20Sopenharmony_ci#define T_TA_SURE_CNT(x) UPDATE(x, 5, 0) 1368c2ecf20Sopenharmony_ci/* Clock/Data0/Data1/Data2/Data3 Lane Register Part: reg12 */ 1378c2ecf20Sopenharmony_ci#define T_TA_WAIT_CNT_MASK GENMASK(5, 0) 1388c2ecf20Sopenharmony_ci#define T_TA_WAIT_CNT(x) UPDATE(x, 5, 0) 1398c2ecf20Sopenharmony_ci/* LVDS Register Part: reg00 */ 1408c2ecf20Sopenharmony_ci#define LVDS_DIGITAL_INTERNAL_RESET_MASK BIT(2) 1418c2ecf20Sopenharmony_ci#define LVDS_DIGITAL_INTERNAL_RESET_DISABLE BIT(2) 1428c2ecf20Sopenharmony_ci#define LVDS_DIGITAL_INTERNAL_RESET_ENABLE 0 1438c2ecf20Sopenharmony_ci/* LVDS Register Part: reg01 */ 1448c2ecf20Sopenharmony_ci#define LVDS_DIGITAL_INTERNAL_ENABLE_MASK BIT(7) 1458c2ecf20Sopenharmony_ci#define LVDS_DIGITAL_INTERNAL_ENABLE BIT(7) 1468c2ecf20Sopenharmony_ci#define LVDS_DIGITAL_INTERNAL_DISABLE 0 1478c2ecf20Sopenharmony_ci/* LVDS Register Part: reg03 */ 1488c2ecf20Sopenharmony_ci#define MODE_ENABLE_MASK GENMASK(2, 0) 1498c2ecf20Sopenharmony_ci#define TTL_MODE_ENABLE BIT(2) 1508c2ecf20Sopenharmony_ci#define LVDS_MODE_ENABLE BIT(1) 1518c2ecf20Sopenharmony_ci#define MIPI_MODE_ENABLE BIT(0) 1528c2ecf20Sopenharmony_ci/* LVDS Register Part: reg0b */ 1538c2ecf20Sopenharmony_ci#define LVDS_LANE_EN_MASK GENMASK(7, 3) 1548c2ecf20Sopenharmony_ci#define LVDS_DATA_LANE0_EN BIT(7) 1558c2ecf20Sopenharmony_ci#define LVDS_DATA_LANE1_EN BIT(6) 1568c2ecf20Sopenharmony_ci#define LVDS_DATA_LANE2_EN BIT(5) 1578c2ecf20Sopenharmony_ci#define LVDS_DATA_LANE3_EN BIT(4) 1588c2ecf20Sopenharmony_ci#define LVDS_CLK_LANE_EN BIT(3) 1598c2ecf20Sopenharmony_ci#define LVDS_PLL_POWER_MASK BIT(2) 1608c2ecf20Sopenharmony_ci#define LVDS_PLL_POWER_OFF BIT(2) 1618c2ecf20Sopenharmony_ci#define LVDS_PLL_POWER_ON 0 1628c2ecf20Sopenharmony_ci#define LVDS_BANDGAP_POWER_MASK BIT(0) 1638c2ecf20Sopenharmony_ci#define LVDS_BANDGAP_POWER_DOWN BIT(0) 1648c2ecf20Sopenharmony_ci#define LVDS_BANDGAP_POWER_ON 0 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_ci#define DSI_PHY_RSTZ 0xa0 1678c2ecf20Sopenharmony_ci#define PHY_ENABLECLK BIT(2) 1688c2ecf20Sopenharmony_ci#define DSI_PHY_STATUS 0xb0 1698c2ecf20Sopenharmony_ci#define PHY_LOCK BIT(0) 1708c2ecf20Sopenharmony_ci 1718c2ecf20Sopenharmony_cistruct inno_dsidphy { 1728c2ecf20Sopenharmony_ci struct device *dev; 1738c2ecf20Sopenharmony_ci struct clk *ref_clk; 1748c2ecf20Sopenharmony_ci struct clk *pclk_phy; 1758c2ecf20Sopenharmony_ci struct clk *pclk_host; 1768c2ecf20Sopenharmony_ci void __iomem *phy_base; 1778c2ecf20Sopenharmony_ci void __iomem *host_base; 1788c2ecf20Sopenharmony_ci struct reset_control *rst; 1798c2ecf20Sopenharmony_ci enum phy_mode mode; 1808c2ecf20Sopenharmony_ci struct phy_configure_opts_mipi_dphy dphy_cfg; 1818c2ecf20Sopenharmony_ci 1828c2ecf20Sopenharmony_ci struct clk *pll_clk; 1838c2ecf20Sopenharmony_ci struct { 1848c2ecf20Sopenharmony_ci struct clk_hw hw; 1858c2ecf20Sopenharmony_ci u8 prediv; 1868c2ecf20Sopenharmony_ci u16 fbdiv; 1878c2ecf20Sopenharmony_ci unsigned long rate; 1888c2ecf20Sopenharmony_ci } pll; 1898c2ecf20Sopenharmony_ci}; 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cienum { 1928c2ecf20Sopenharmony_ci REGISTER_PART_ANALOG, 1938c2ecf20Sopenharmony_ci REGISTER_PART_DIGITAL, 1948c2ecf20Sopenharmony_ci REGISTER_PART_CLOCK_LANE, 1958c2ecf20Sopenharmony_ci REGISTER_PART_DATA0_LANE, 1968c2ecf20Sopenharmony_ci REGISTER_PART_DATA1_LANE, 1978c2ecf20Sopenharmony_ci REGISTER_PART_DATA2_LANE, 1988c2ecf20Sopenharmony_ci REGISTER_PART_DATA3_LANE, 1998c2ecf20Sopenharmony_ci REGISTER_PART_LVDS, 2008c2ecf20Sopenharmony_ci}; 2018c2ecf20Sopenharmony_ci 2028c2ecf20Sopenharmony_cistatic inline struct inno_dsidphy *hw_to_inno(struct clk_hw *hw) 2038c2ecf20Sopenharmony_ci{ 2048c2ecf20Sopenharmony_ci return container_of(hw, struct inno_dsidphy, pll.hw); 2058c2ecf20Sopenharmony_ci} 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_cistatic void phy_update_bits(struct inno_dsidphy *inno, 2088c2ecf20Sopenharmony_ci u8 first, u8 second, u8 mask, u8 val) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci u32 reg = PHY_REG(first, second) << 2; 2118c2ecf20Sopenharmony_ci unsigned int tmp, orig; 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci orig = readl(inno->phy_base + reg); 2148c2ecf20Sopenharmony_ci tmp = orig & ~mask; 2158c2ecf20Sopenharmony_ci tmp |= val & mask; 2168c2ecf20Sopenharmony_ci writel(tmp, inno->phy_base + reg); 2178c2ecf20Sopenharmony_ci} 2188c2ecf20Sopenharmony_ci 2198c2ecf20Sopenharmony_cistatic unsigned long inno_dsidphy_pll_calc_rate(struct inno_dsidphy *inno, 2208c2ecf20Sopenharmony_ci unsigned long rate) 2218c2ecf20Sopenharmony_ci{ 2228c2ecf20Sopenharmony_ci unsigned long prate = clk_get_rate(inno->ref_clk); 2238c2ecf20Sopenharmony_ci unsigned long best_freq = 0; 2248c2ecf20Sopenharmony_ci unsigned long fref, fout; 2258c2ecf20Sopenharmony_ci u8 min_prediv, max_prediv; 2268c2ecf20Sopenharmony_ci u8 _prediv, best_prediv = 1; 2278c2ecf20Sopenharmony_ci u16 _fbdiv, best_fbdiv = 1; 2288c2ecf20Sopenharmony_ci u32 min_delta = UINT_MAX; 2298c2ecf20Sopenharmony_ci 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * The PLL output frequency can be calculated using a simple formula: 2328c2ecf20Sopenharmony_ci * PLL_Output_Frequency = (FREF / PREDIV * FBDIV) / 2 2338c2ecf20Sopenharmony_ci * PLL_Output_Frequency: it is equal to DDR-Clock-Frequency * 2 2348c2ecf20Sopenharmony_ci */ 2358c2ecf20Sopenharmony_ci fref = prate / 2; 2368c2ecf20Sopenharmony_ci if (rate > 1000000000UL) 2378c2ecf20Sopenharmony_ci fout = 1000000000UL; 2388c2ecf20Sopenharmony_ci else 2398c2ecf20Sopenharmony_ci fout = rate; 2408c2ecf20Sopenharmony_ci 2418c2ecf20Sopenharmony_ci /* 5Mhz < Fref / prediv < 40MHz */ 2428c2ecf20Sopenharmony_ci min_prediv = DIV_ROUND_UP(fref, 40000000); 2438c2ecf20Sopenharmony_ci max_prediv = fref / 5000000; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci for (_prediv = min_prediv; _prediv <= max_prediv; _prediv++) { 2468c2ecf20Sopenharmony_ci u64 tmp; 2478c2ecf20Sopenharmony_ci u32 delta; 2488c2ecf20Sopenharmony_ci 2498c2ecf20Sopenharmony_ci tmp = (u64)fout * _prediv; 2508c2ecf20Sopenharmony_ci do_div(tmp, fref); 2518c2ecf20Sopenharmony_ci _fbdiv = tmp; 2528c2ecf20Sopenharmony_ci 2538c2ecf20Sopenharmony_ci /* 2548c2ecf20Sopenharmony_ci * The possible settings of feedback divider are 2558c2ecf20Sopenharmony_ci * 12, 13, 14, 16, ~ 511 2568c2ecf20Sopenharmony_ci */ 2578c2ecf20Sopenharmony_ci if (_fbdiv == 15) 2588c2ecf20Sopenharmony_ci continue; 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_ci if (_fbdiv < 12 || _fbdiv > 511) 2618c2ecf20Sopenharmony_ci continue; 2628c2ecf20Sopenharmony_ci 2638c2ecf20Sopenharmony_ci tmp = (u64)_fbdiv * fref; 2648c2ecf20Sopenharmony_ci do_div(tmp, _prediv); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci delta = abs(fout - tmp); 2678c2ecf20Sopenharmony_ci if (!delta) { 2688c2ecf20Sopenharmony_ci best_prediv = _prediv; 2698c2ecf20Sopenharmony_ci best_fbdiv = _fbdiv; 2708c2ecf20Sopenharmony_ci best_freq = tmp; 2718c2ecf20Sopenharmony_ci break; 2728c2ecf20Sopenharmony_ci } else if (delta < min_delta) { 2738c2ecf20Sopenharmony_ci best_prediv = _prediv; 2748c2ecf20Sopenharmony_ci best_fbdiv = _fbdiv; 2758c2ecf20Sopenharmony_ci best_freq = tmp; 2768c2ecf20Sopenharmony_ci min_delta = delta; 2778c2ecf20Sopenharmony_ci } 2788c2ecf20Sopenharmony_ci } 2798c2ecf20Sopenharmony_ci 2808c2ecf20Sopenharmony_ci if (best_freq) { 2818c2ecf20Sopenharmony_ci inno->pll.prediv = best_prediv; 2828c2ecf20Sopenharmony_ci inno->pll.fbdiv = best_fbdiv; 2838c2ecf20Sopenharmony_ci inno->pll.rate = best_freq; 2848c2ecf20Sopenharmony_ci } 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return best_freq; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void inno_dsidphy_mipi_mode_enable(struct inno_dsidphy *inno) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci struct phy_configure_opts_mipi_dphy *cfg = &inno->dphy_cfg; 2928c2ecf20Sopenharmony_ci const struct { 2938c2ecf20Sopenharmony_ci unsigned long rate; 2948c2ecf20Sopenharmony_ci u8 hs_prepare; 2958c2ecf20Sopenharmony_ci u8 clk_lane_hs_zero; 2968c2ecf20Sopenharmony_ci u8 data_lane_hs_zero; 2978c2ecf20Sopenharmony_ci u8 hs_trail; 2988c2ecf20Sopenharmony_ci } timings[] = { 2998c2ecf20Sopenharmony_ci { 110000000, 0x20, 0x16, 0x02, 0x22}, 3008c2ecf20Sopenharmony_ci { 150000000, 0x06, 0x16, 0x03, 0x45}, 3018c2ecf20Sopenharmony_ci { 200000000, 0x18, 0x17, 0x04, 0x0b}, 3028c2ecf20Sopenharmony_ci { 250000000, 0x05, 0x17, 0x05, 0x16}, 3038c2ecf20Sopenharmony_ci { 300000000, 0x51, 0x18, 0x06, 0x2c}, 3048c2ecf20Sopenharmony_ci { 400000000, 0x64, 0x19, 0x07, 0x33}, 3058c2ecf20Sopenharmony_ci { 500000000, 0x20, 0x1b, 0x07, 0x4e}, 3068c2ecf20Sopenharmony_ci { 600000000, 0x6a, 0x1d, 0x08, 0x3a}, 3078c2ecf20Sopenharmony_ci { 700000000, 0x3e, 0x1e, 0x08, 0x6a}, 3088c2ecf20Sopenharmony_ci { 800000000, 0x21, 0x1f, 0x09, 0x29}, 3098c2ecf20Sopenharmony_ci {1000000000, 0x09, 0x20, 0x09, 0x27}, 3108c2ecf20Sopenharmony_ci }; 3118c2ecf20Sopenharmony_ci u32 t_txbyteclkhs, t_txclkesc; 3128c2ecf20Sopenharmony_ci u32 txbyteclkhs, txclkesc, esc_clk_div; 3138c2ecf20Sopenharmony_ci u32 hs_exit, clk_post, clk_pre, wakeup, lpx, ta_go, ta_sure, ta_wait; 3148c2ecf20Sopenharmony_ci u32 hs_prepare, hs_trail, hs_zero, clk_lane_hs_zero, data_lane_hs_zero; 3158c2ecf20Sopenharmony_ci unsigned int i; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci inno_dsidphy_pll_calc_rate(inno, cfg->hs_clk_rate); 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci /* Select MIPI mode */ 3208c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x03, 3218c2ecf20Sopenharmony_ci MODE_ENABLE_MASK, MIPI_MODE_ENABLE); 3228c2ecf20Sopenharmony_ci /* Configure PLL */ 3238c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x03, 3248c2ecf20Sopenharmony_ci REG_PREDIV_MASK, REG_PREDIV(inno->pll.prediv)); 3258c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x03, 3268c2ecf20Sopenharmony_ci REG_FBDIV_HI_MASK, REG_FBDIV_HI(inno->pll.fbdiv)); 3278c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x04, 3288c2ecf20Sopenharmony_ci REG_FBDIV_LO_MASK, REG_FBDIV_LO(inno->pll.fbdiv)); 3298c2ecf20Sopenharmony_ci /* Enable PLL and LDO */ 3308c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x01, 3318c2ecf20Sopenharmony_ci REG_LDOPD_MASK | REG_PLLPD_MASK, 3328c2ecf20Sopenharmony_ci REG_LDOPD_POWER_ON | REG_PLLPD_POWER_ON); 3338c2ecf20Sopenharmony_ci /* Reset analog */ 3348c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x01, 3358c2ecf20Sopenharmony_ci REG_SYNCRST_MASK, REG_SYNCRST_RESET); 3368c2ecf20Sopenharmony_ci udelay(1); 3378c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x01, 3388c2ecf20Sopenharmony_ci REG_SYNCRST_MASK, REG_SYNCRST_NORMAL); 3398c2ecf20Sopenharmony_ci /* Reset digital */ 3408c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_DIGITAL, 0x00, 3418c2ecf20Sopenharmony_ci REG_DIG_RSTN_MASK, REG_DIG_RSTN_RESET); 3428c2ecf20Sopenharmony_ci udelay(1); 3438c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_DIGITAL, 0x00, 3448c2ecf20Sopenharmony_ci REG_DIG_RSTN_MASK, REG_DIG_RSTN_NORMAL); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci txbyteclkhs = inno->pll.rate / 8; 3478c2ecf20Sopenharmony_ci t_txbyteclkhs = div_u64(PSEC_PER_SEC, txbyteclkhs); 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_ci esc_clk_div = DIV_ROUND_UP(txbyteclkhs, 20000000); 3508c2ecf20Sopenharmony_ci txclkesc = txbyteclkhs / esc_clk_div; 3518c2ecf20Sopenharmony_ci t_txclkesc = div_u64(PSEC_PER_SEC, txclkesc); 3528c2ecf20Sopenharmony_ci 3538c2ecf20Sopenharmony_ci /* 3548c2ecf20Sopenharmony_ci * The value of counter for HS Ths-exit 3558c2ecf20Sopenharmony_ci * Ths-exit = Tpin_txbyteclkhs * value 3568c2ecf20Sopenharmony_ci */ 3578c2ecf20Sopenharmony_ci hs_exit = DIV_ROUND_UP(cfg->hs_exit, t_txbyteclkhs); 3588c2ecf20Sopenharmony_ci /* 3598c2ecf20Sopenharmony_ci * The value of counter for HS Tclk-post 3608c2ecf20Sopenharmony_ci * Tclk-post = Tpin_txbyteclkhs * value 3618c2ecf20Sopenharmony_ci */ 3628c2ecf20Sopenharmony_ci clk_post = DIV_ROUND_UP(cfg->clk_post, t_txbyteclkhs); 3638c2ecf20Sopenharmony_ci /* 3648c2ecf20Sopenharmony_ci * The value of counter for HS Tclk-pre 3658c2ecf20Sopenharmony_ci * Tclk-pre = Tpin_txbyteclkhs * value 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci clk_pre = DIV_ROUND_UP(cfg->clk_pre, t_txbyteclkhs); 3688c2ecf20Sopenharmony_ci 3698c2ecf20Sopenharmony_ci /* 3708c2ecf20Sopenharmony_ci * The value of counter for HS Tlpx Time 3718c2ecf20Sopenharmony_ci * Tlpx = Tpin_txbyteclkhs * (2 + value) 3728c2ecf20Sopenharmony_ci */ 3738c2ecf20Sopenharmony_ci lpx = DIV_ROUND_UP(cfg->lpx, t_txbyteclkhs); 3748c2ecf20Sopenharmony_ci if (lpx >= 2) 3758c2ecf20Sopenharmony_ci lpx -= 2; 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci /* 3788c2ecf20Sopenharmony_ci * The value of counter for HS Tta-go 3798c2ecf20Sopenharmony_ci * Tta-go for turnaround 3808c2ecf20Sopenharmony_ci * Tta-go = Ttxclkesc * value 3818c2ecf20Sopenharmony_ci */ 3828c2ecf20Sopenharmony_ci ta_go = DIV_ROUND_UP(cfg->ta_go, t_txclkesc); 3838c2ecf20Sopenharmony_ci /* 3848c2ecf20Sopenharmony_ci * The value of counter for HS Tta-sure 3858c2ecf20Sopenharmony_ci * Tta-sure for turnaround 3868c2ecf20Sopenharmony_ci * Tta-sure = Ttxclkesc * value 3878c2ecf20Sopenharmony_ci */ 3888c2ecf20Sopenharmony_ci ta_sure = DIV_ROUND_UP(cfg->ta_sure, t_txclkesc); 3898c2ecf20Sopenharmony_ci /* 3908c2ecf20Sopenharmony_ci * The value of counter for HS Tta-wait 3918c2ecf20Sopenharmony_ci * Tta-wait for turnaround 3928c2ecf20Sopenharmony_ci * Tta-wait = Ttxclkesc * value 3938c2ecf20Sopenharmony_ci */ 3948c2ecf20Sopenharmony_ci ta_wait = DIV_ROUND_UP(cfg->ta_get, t_txclkesc); 3958c2ecf20Sopenharmony_ci 3968c2ecf20Sopenharmony_ci for (i = 0; i < ARRAY_SIZE(timings); i++) 3978c2ecf20Sopenharmony_ci if (inno->pll.rate <= timings[i].rate) 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci 4008c2ecf20Sopenharmony_ci if (i == ARRAY_SIZE(timings)) 4018c2ecf20Sopenharmony_ci --i; 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci hs_prepare = timings[i].hs_prepare; 4048c2ecf20Sopenharmony_ci hs_trail = timings[i].hs_trail; 4058c2ecf20Sopenharmony_ci clk_lane_hs_zero = timings[i].clk_lane_hs_zero; 4068c2ecf20Sopenharmony_ci data_lane_hs_zero = timings[i].data_lane_hs_zero; 4078c2ecf20Sopenharmony_ci wakeup = 0x3ff; 4088c2ecf20Sopenharmony_ci 4098c2ecf20Sopenharmony_ci for (i = REGISTER_PART_CLOCK_LANE; i <= REGISTER_PART_DATA3_LANE; i++) { 4108c2ecf20Sopenharmony_ci if (i == REGISTER_PART_CLOCK_LANE) 4118c2ecf20Sopenharmony_ci hs_zero = clk_lane_hs_zero; 4128c2ecf20Sopenharmony_ci else 4138c2ecf20Sopenharmony_ci hs_zero = data_lane_hs_zero; 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x05, T_LPX_CNT_MASK, 4168c2ecf20Sopenharmony_ci T_LPX_CNT(lpx)); 4178c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x06, T_HS_PREPARE_CNT_MASK, 4188c2ecf20Sopenharmony_ci T_HS_PREPARE_CNT(hs_prepare)); 4198c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x07, T_HS_ZERO_CNT_MASK, 4208c2ecf20Sopenharmony_ci T_HS_ZERO_CNT(hs_zero)); 4218c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x08, T_HS_TRAIL_CNT_MASK, 4228c2ecf20Sopenharmony_ci T_HS_TRAIL_CNT(hs_trail)); 4238c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x09, T_HS_EXIT_CNT_MASK, 4248c2ecf20Sopenharmony_ci T_HS_EXIT_CNT(hs_exit)); 4258c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x0a, T_CLK_POST_CNT_MASK, 4268c2ecf20Sopenharmony_ci T_CLK_POST_CNT(clk_post)); 4278c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x0e, T_CLK_PRE_CNT_MASK, 4288c2ecf20Sopenharmony_ci T_CLK_PRE_CNT(clk_pre)); 4298c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x0c, T_WAKEUP_CNT_HI_MASK, 4308c2ecf20Sopenharmony_ci T_WAKEUP_CNT_HI(wakeup >> 8)); 4318c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x0d, T_WAKEUP_CNT_LO_MASK, 4328c2ecf20Sopenharmony_ci T_WAKEUP_CNT_LO(wakeup)); 4338c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x10, T_TA_GO_CNT_MASK, 4348c2ecf20Sopenharmony_ci T_TA_GO_CNT(ta_go)); 4358c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x11, T_TA_SURE_CNT_MASK, 4368c2ecf20Sopenharmony_ci T_TA_SURE_CNT(ta_sure)); 4378c2ecf20Sopenharmony_ci phy_update_bits(inno, i, 0x12, T_TA_WAIT_CNT_MASK, 4388c2ecf20Sopenharmony_ci T_TA_WAIT_CNT(ta_wait)); 4398c2ecf20Sopenharmony_ci } 4408c2ecf20Sopenharmony_ci 4418c2ecf20Sopenharmony_ci /* Enable all lanes on analog part */ 4428c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x00, 4438c2ecf20Sopenharmony_ci LANE_EN_MASK, LANE_EN_CK | LANE_EN_3 | LANE_EN_2 | 4448c2ecf20Sopenharmony_ci LANE_EN_1 | LANE_EN_0); 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void inno_dsidphy_lvds_mode_enable(struct inno_dsidphy *inno) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci u8 prediv = 2; 4508c2ecf20Sopenharmony_ci u16 fbdiv = 28; 4518c2ecf20Sopenharmony_ci 4528c2ecf20Sopenharmony_ci /* Sample clock reverse direction */ 4538c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x08, 4548c2ecf20Sopenharmony_ci SAMPLE_CLOCK_DIRECTION_MASK, 4558c2ecf20Sopenharmony_ci SAMPLE_CLOCK_DIRECTION_REVERSE); 4568c2ecf20Sopenharmony_ci 4578c2ecf20Sopenharmony_ci /* Select LVDS mode */ 4588c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x03, 4598c2ecf20Sopenharmony_ci MODE_ENABLE_MASK, LVDS_MODE_ENABLE); 4608c2ecf20Sopenharmony_ci /* Configure PLL */ 4618c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x03, 4628c2ecf20Sopenharmony_ci REG_PREDIV_MASK, REG_PREDIV(prediv)); 4638c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x03, 4648c2ecf20Sopenharmony_ci REG_FBDIV_HI_MASK, REG_FBDIV_HI(fbdiv)); 4658c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x04, 4668c2ecf20Sopenharmony_ci REG_FBDIV_LO_MASK, REG_FBDIV_LO(fbdiv)); 4678c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x08, 0xff, 0xfc); 4688c2ecf20Sopenharmony_ci /* Enable PLL and Bandgap */ 4698c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x0b, 4708c2ecf20Sopenharmony_ci LVDS_PLL_POWER_MASK | LVDS_BANDGAP_POWER_MASK, 4718c2ecf20Sopenharmony_ci LVDS_PLL_POWER_ON | LVDS_BANDGAP_POWER_ON); 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci msleep(20); 4748c2ecf20Sopenharmony_ci 4758c2ecf20Sopenharmony_ci /* Reset LVDS digital logic */ 4768c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x00, 4778c2ecf20Sopenharmony_ci LVDS_DIGITAL_INTERNAL_RESET_MASK, 4788c2ecf20Sopenharmony_ci LVDS_DIGITAL_INTERNAL_RESET_ENABLE); 4798c2ecf20Sopenharmony_ci udelay(1); 4808c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x00, 4818c2ecf20Sopenharmony_ci LVDS_DIGITAL_INTERNAL_RESET_MASK, 4828c2ecf20Sopenharmony_ci LVDS_DIGITAL_INTERNAL_RESET_DISABLE); 4838c2ecf20Sopenharmony_ci /* Enable LVDS digital logic */ 4848c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x01, 4858c2ecf20Sopenharmony_ci LVDS_DIGITAL_INTERNAL_ENABLE_MASK, 4868c2ecf20Sopenharmony_ci LVDS_DIGITAL_INTERNAL_ENABLE); 4878c2ecf20Sopenharmony_ci /* Enable LVDS analog driver */ 4888c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x0b, 4898c2ecf20Sopenharmony_ci LVDS_LANE_EN_MASK, LVDS_CLK_LANE_EN | 4908c2ecf20Sopenharmony_ci LVDS_DATA_LANE0_EN | LVDS_DATA_LANE1_EN | 4918c2ecf20Sopenharmony_ci LVDS_DATA_LANE2_EN | LVDS_DATA_LANE3_EN); 4928c2ecf20Sopenharmony_ci} 4938c2ecf20Sopenharmony_ci 4948c2ecf20Sopenharmony_cistatic int inno_dsidphy_power_on(struct phy *phy) 4958c2ecf20Sopenharmony_ci{ 4968c2ecf20Sopenharmony_ci struct inno_dsidphy *inno = phy_get_drvdata(phy); 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci clk_prepare_enable(inno->pclk_phy); 4998c2ecf20Sopenharmony_ci clk_prepare_enable(inno->ref_clk); 5008c2ecf20Sopenharmony_ci pm_runtime_get_sync(inno->dev); 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci /* Bandgap power on */ 5038c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x00, 5048c2ecf20Sopenharmony_ci BANDGAP_POWER_MASK, BANDGAP_POWER_ON); 5058c2ecf20Sopenharmony_ci /* Enable power work */ 5068c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x00, 5078c2ecf20Sopenharmony_ci POWER_WORK_MASK, POWER_WORK_ENABLE); 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci switch (inno->mode) { 5108c2ecf20Sopenharmony_ci case PHY_MODE_MIPI_DPHY: 5118c2ecf20Sopenharmony_ci inno_dsidphy_mipi_mode_enable(inno); 5128c2ecf20Sopenharmony_ci break; 5138c2ecf20Sopenharmony_ci case PHY_MODE_LVDS: 5148c2ecf20Sopenharmony_ci inno_dsidphy_lvds_mode_enable(inno); 5158c2ecf20Sopenharmony_ci break; 5168c2ecf20Sopenharmony_ci default: 5178c2ecf20Sopenharmony_ci return -EINVAL; 5188c2ecf20Sopenharmony_ci } 5198c2ecf20Sopenharmony_ci 5208c2ecf20Sopenharmony_ci return 0; 5218c2ecf20Sopenharmony_ci} 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_cistatic int inno_dsidphy_power_off(struct phy *phy) 5248c2ecf20Sopenharmony_ci{ 5258c2ecf20Sopenharmony_ci struct inno_dsidphy *inno = phy_get_drvdata(phy); 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x00, LANE_EN_MASK, 0); 5288c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x01, 5298c2ecf20Sopenharmony_ci REG_LDOPD_MASK | REG_PLLPD_MASK, 5308c2ecf20Sopenharmony_ci REG_LDOPD_POWER_DOWN | REG_PLLPD_POWER_DOWN); 5318c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x00, 5328c2ecf20Sopenharmony_ci POWER_WORK_MASK, POWER_WORK_DISABLE); 5338c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_ANALOG, 0x00, 5348c2ecf20Sopenharmony_ci BANDGAP_POWER_MASK, BANDGAP_POWER_DOWN); 5358c2ecf20Sopenharmony_ci 5368c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x0b, LVDS_LANE_EN_MASK, 0); 5378c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x01, 5388c2ecf20Sopenharmony_ci LVDS_DIGITAL_INTERNAL_ENABLE_MASK, 5398c2ecf20Sopenharmony_ci LVDS_DIGITAL_INTERNAL_DISABLE); 5408c2ecf20Sopenharmony_ci phy_update_bits(inno, REGISTER_PART_LVDS, 0x0b, 5418c2ecf20Sopenharmony_ci LVDS_PLL_POWER_MASK | LVDS_BANDGAP_POWER_MASK, 5428c2ecf20Sopenharmony_ci LVDS_PLL_POWER_OFF | LVDS_BANDGAP_POWER_DOWN); 5438c2ecf20Sopenharmony_ci 5448c2ecf20Sopenharmony_ci pm_runtime_put(inno->dev); 5458c2ecf20Sopenharmony_ci clk_disable_unprepare(inno->ref_clk); 5468c2ecf20Sopenharmony_ci clk_disable_unprepare(inno->pclk_phy); 5478c2ecf20Sopenharmony_ci 5488c2ecf20Sopenharmony_ci return 0; 5498c2ecf20Sopenharmony_ci} 5508c2ecf20Sopenharmony_ci 5518c2ecf20Sopenharmony_cistatic int inno_dsidphy_set_mode(struct phy *phy, enum phy_mode mode, 5528c2ecf20Sopenharmony_ci int submode) 5538c2ecf20Sopenharmony_ci{ 5548c2ecf20Sopenharmony_ci struct inno_dsidphy *inno = phy_get_drvdata(phy); 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci switch (mode) { 5578c2ecf20Sopenharmony_ci case PHY_MODE_MIPI_DPHY: 5588c2ecf20Sopenharmony_ci case PHY_MODE_LVDS: 5598c2ecf20Sopenharmony_ci inno->mode = mode; 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci default: 5628c2ecf20Sopenharmony_ci return -EINVAL; 5638c2ecf20Sopenharmony_ci } 5648c2ecf20Sopenharmony_ci 5658c2ecf20Sopenharmony_ci return 0; 5668c2ecf20Sopenharmony_ci} 5678c2ecf20Sopenharmony_ci 5688c2ecf20Sopenharmony_cistatic int inno_dsidphy_configure(struct phy *phy, 5698c2ecf20Sopenharmony_ci union phy_configure_opts *opts) 5708c2ecf20Sopenharmony_ci{ 5718c2ecf20Sopenharmony_ci struct inno_dsidphy *inno = phy_get_drvdata(phy); 5728c2ecf20Sopenharmony_ci int ret; 5738c2ecf20Sopenharmony_ci 5748c2ecf20Sopenharmony_ci if (inno->mode != PHY_MODE_MIPI_DPHY) 5758c2ecf20Sopenharmony_ci return -EINVAL; 5768c2ecf20Sopenharmony_ci 5778c2ecf20Sopenharmony_ci ret = phy_mipi_dphy_config_validate(&opts->mipi_dphy); 5788c2ecf20Sopenharmony_ci if (ret) 5798c2ecf20Sopenharmony_ci return ret; 5808c2ecf20Sopenharmony_ci 5818c2ecf20Sopenharmony_ci memcpy(&inno->dphy_cfg, &opts->mipi_dphy, sizeof(inno->dphy_cfg)); 5828c2ecf20Sopenharmony_ci 5838c2ecf20Sopenharmony_ci return 0; 5848c2ecf20Sopenharmony_ci} 5858c2ecf20Sopenharmony_ci 5868c2ecf20Sopenharmony_cistatic const struct phy_ops inno_dsidphy_ops = { 5878c2ecf20Sopenharmony_ci .configure = inno_dsidphy_configure, 5888c2ecf20Sopenharmony_ci .set_mode = inno_dsidphy_set_mode, 5898c2ecf20Sopenharmony_ci .power_on = inno_dsidphy_power_on, 5908c2ecf20Sopenharmony_ci .power_off = inno_dsidphy_power_off, 5918c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 5928c2ecf20Sopenharmony_ci}; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic int inno_dsidphy_probe(struct platform_device *pdev) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct device *dev = &pdev->dev; 5978c2ecf20Sopenharmony_ci struct inno_dsidphy *inno; 5988c2ecf20Sopenharmony_ci struct phy_provider *phy_provider; 5998c2ecf20Sopenharmony_ci struct phy *phy; 6008c2ecf20Sopenharmony_ci int ret; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci inno = devm_kzalloc(dev, sizeof(*inno), GFP_KERNEL); 6038c2ecf20Sopenharmony_ci if (!inno) 6048c2ecf20Sopenharmony_ci return -ENOMEM; 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci inno->dev = dev; 6078c2ecf20Sopenharmony_ci platform_set_drvdata(pdev, inno); 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_ci inno->phy_base = devm_platform_ioremap_resource(pdev, 0); 6108c2ecf20Sopenharmony_ci if (IS_ERR(inno->phy_base)) 6118c2ecf20Sopenharmony_ci return PTR_ERR(inno->phy_base); 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci inno->ref_clk = devm_clk_get(dev, "ref"); 6148c2ecf20Sopenharmony_ci if (IS_ERR(inno->ref_clk)) { 6158c2ecf20Sopenharmony_ci ret = PTR_ERR(inno->ref_clk); 6168c2ecf20Sopenharmony_ci dev_err(dev, "failed to get ref clock: %d\n", ret); 6178c2ecf20Sopenharmony_ci return ret; 6188c2ecf20Sopenharmony_ci } 6198c2ecf20Sopenharmony_ci 6208c2ecf20Sopenharmony_ci inno->pclk_phy = devm_clk_get(dev, "pclk"); 6218c2ecf20Sopenharmony_ci if (IS_ERR(inno->pclk_phy)) { 6228c2ecf20Sopenharmony_ci ret = PTR_ERR(inno->pclk_phy); 6238c2ecf20Sopenharmony_ci dev_err(dev, "failed to get phy pclk: %d\n", ret); 6248c2ecf20Sopenharmony_ci return ret; 6258c2ecf20Sopenharmony_ci } 6268c2ecf20Sopenharmony_ci 6278c2ecf20Sopenharmony_ci inno->rst = devm_reset_control_get(dev, "apb"); 6288c2ecf20Sopenharmony_ci if (IS_ERR(inno->rst)) { 6298c2ecf20Sopenharmony_ci ret = PTR_ERR(inno->rst); 6308c2ecf20Sopenharmony_ci dev_err(dev, "failed to get system reset control: %d\n", ret); 6318c2ecf20Sopenharmony_ci return ret; 6328c2ecf20Sopenharmony_ci } 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci phy = devm_phy_create(dev, NULL, &inno_dsidphy_ops); 6358c2ecf20Sopenharmony_ci if (IS_ERR(phy)) { 6368c2ecf20Sopenharmony_ci ret = PTR_ERR(phy); 6378c2ecf20Sopenharmony_ci dev_err(dev, "failed to create phy: %d\n", ret); 6388c2ecf20Sopenharmony_ci return ret; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci phy_set_drvdata(phy, inno); 6428c2ecf20Sopenharmony_ci 6438c2ecf20Sopenharmony_ci phy_provider = devm_of_phy_provider_register(dev, of_phy_simple_xlate); 6448c2ecf20Sopenharmony_ci if (IS_ERR(phy_provider)) { 6458c2ecf20Sopenharmony_ci ret = PTR_ERR(phy_provider); 6468c2ecf20Sopenharmony_ci dev_err(dev, "failed to register phy provider: %d\n", ret); 6478c2ecf20Sopenharmony_ci return ret; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci 6508c2ecf20Sopenharmony_ci pm_runtime_enable(dev); 6518c2ecf20Sopenharmony_ci 6528c2ecf20Sopenharmony_ci return 0; 6538c2ecf20Sopenharmony_ci} 6548c2ecf20Sopenharmony_ci 6558c2ecf20Sopenharmony_cistatic int inno_dsidphy_remove(struct platform_device *pdev) 6568c2ecf20Sopenharmony_ci{ 6578c2ecf20Sopenharmony_ci struct inno_dsidphy *inno = platform_get_drvdata(pdev); 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci pm_runtime_disable(inno->dev); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci return 0; 6628c2ecf20Sopenharmony_ci} 6638c2ecf20Sopenharmony_ci 6648c2ecf20Sopenharmony_cistatic const struct of_device_id inno_dsidphy_of_match[] = { 6658c2ecf20Sopenharmony_ci { .compatible = "rockchip,px30-dsi-dphy", }, 6668c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3128-dsi-dphy", }, 6678c2ecf20Sopenharmony_ci { .compatible = "rockchip,rk3368-dsi-dphy", }, 6688c2ecf20Sopenharmony_ci {} 6698c2ecf20Sopenharmony_ci}; 6708c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(of, inno_dsidphy_of_match); 6718c2ecf20Sopenharmony_ci 6728c2ecf20Sopenharmony_cistatic struct platform_driver inno_dsidphy_driver = { 6738c2ecf20Sopenharmony_ci .driver = { 6748c2ecf20Sopenharmony_ci .name = "inno-dsidphy", 6758c2ecf20Sopenharmony_ci .of_match_table = of_match_ptr(inno_dsidphy_of_match), 6768c2ecf20Sopenharmony_ci }, 6778c2ecf20Sopenharmony_ci .probe = inno_dsidphy_probe, 6788c2ecf20Sopenharmony_ci .remove = inno_dsidphy_remove, 6798c2ecf20Sopenharmony_ci}; 6808c2ecf20Sopenharmony_cimodule_platform_driver(inno_dsidphy_driver); 6818c2ecf20Sopenharmony_ci 6828c2ecf20Sopenharmony_ciMODULE_AUTHOR("Wyon Bi <bivvy.bi@rock-chips.com>"); 6838c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Innosilicon MIPI/LVDS/TTL Video Combo PHY driver"); 6848c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 685