// SPDX-License-Identifier: GPL-2.0 /* * Copyright (c) 2018-2019 Synopsys, Inc. and/or its affiliates. * * Synopsys DesignWare MIPI D-PHY controller driver. * SysFS components for the platform driver * * Author: Luis Oliveira */ //#define DEBUG 1 #include "dw-dphy-rx.h" #include "bm_csi_hw.h" static ssize_t dphy_reset_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; char buffer[15]; dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 0); usleep_range(100, 200); dw_dphy_write(dphy, R_CSI2_DPHY_RSTZ, 1); return strlcpy(buf, buffer, PAGE_SIZE); } static ssize_t dphy_freq_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; unsigned long freq; struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; ret = kstrtoul(buf, 10, &freq); if (ret < 0) return ret; if (freq > 2500) { dev_info(dev, "Freq must be under 2500 Mhz\n"); return count; } if (freq < 80) { dev_info(dev, "Freq must be over 80 Mhz\n"); return count; } dev_vdbg(dev, "Data Rate %lu Mbps\n", freq); dphy->dphy_freq = freq*1000; return count; } static ssize_t dphy_freq_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; char buffer[15]; snprintf(buffer, sizeof(buffer), "Freq %d\n", dphy->dphy_freq); return strlcpy(buf, buffer, PAGE_SIZE); } static ssize_t dphy_addr_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; unsigned long addr; int ret; ret = kstrtoul(buf, 10, &addr); if (ret < 0) return ret; //payload = (u16)val; //addr = (u16)(val >> 16); //dev_vdbg(dev, "addr 0x%lX\n", val); //dev_vdbg(dev, "payload: 0x%X\n", addr); //dev_vdbg(dev, "Addr [0x%x] -> 0x%x\n", (unsigned int)addr, // dw_dphy_te_read(dphy, addr)); printk("<0>""addr 0x%lX\n", addr); printk("<0>""Addr [0x%x] -> 0x%x\n", (unsigned int)addr, dw_dphy_te_read(dphy, addr)); return count; } #if IS_ENABLED(CONFIG_DWC_MIPI_TC_DPHY_GEN3) #if 0 static ssize_t idelay_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; char buffer[15]; snprintf(buffer, sizeof(buffer), "idelay %d\n", dw_dphy_if_get_idelay(dphy)); return strlcpy(buf, buffer, PAGE_SIZE); } static ssize_t idelay_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; unsigned long val; u8 lane, delay; int ret; ret = kstrtoul(buf, 16, &val); if (ret < 0) return ret; lane = (u8)val; delay = (u8)(val >> 8); dev_vdbg(dev, "Lanes %u\n", lane); dev_vdbg(dev, "Delay %u\n", delay); dw_dphy_if_set_idelay_lane(dphy, delay, lane); return count; } #endif #endif static ssize_t len_config_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; unsigned long length; int ret; ret = kstrtoul(buf, 10, &length); if (ret < 0) return ret; if (length == BIT8) dev_vdbg(dev, "Configured for 8-bit interface\n"); else if (length == BIT12) dev_vdbg(dev, "Configured for 12-bit interface\n"); else return count; dphy->dphy_te_len = length; return count; } static ssize_t len_config_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; char buffer[20]; snprintf(buffer, sizeof(buffer), "Length %d\n", dphy->dphy_te_len); return strlcpy(buf, buffer, PAGE_SIZE); } static ssize_t dw_dphy_g118_settle_store(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; unsigned long lp_time; int ret; ret = kstrtoul(buf, 10, &lp_time); if (ret < 0) return ret; if (lp_time > 1 && lp_time < 10000) { dphy->lp_time = lp_time; } else { dev_vdbg(dev, "Invalid Value configuring for 1000 ns\n"); dphy->lp_time = 1000; } dphy->lp_time = lp_time; return count; } static ssize_t dw_dphy_g118_settle_show(struct device *dev, struct device_attribute *attr, char *buf) { struct platform_device *pdev = to_platform_device(dev); struct bm_csi_drvdata *drvdata = platform_get_drvdata(pdev); struct dw_dphy_rx *dphy = drvdata->dphy; char buffer[10]; snprintf(buffer, sizeof(buffer), "Settle %d ns\n", dphy->lp_time); return strlcpy(buf, buffer, PAGE_SIZE); } static DEVICE_ATTR_RO(dphy_reset); static DEVICE_ATTR_RW(dphy_freq); static DEVICE_ATTR_WO(dphy_addr); #if IS_ENABLED(CONFIG_DWC_MIPI_TC_DPHY_GEN3) //static DEVICE_ATTR_RW(idelay); #endif static DEVICE_ATTR_RW(len_config); static DEVICE_ATTR_RW(dw_dphy_g118_settle); int dw_dphy_create_capabilities_sysfs(struct platform_device *pdev) { device_create_file(&pdev->dev, &dev_attr_dphy_reset); device_create_file(&pdev->dev, &dev_attr_dphy_freq); device_create_file(&pdev->dev, &dev_attr_dphy_addr); #if IS_ENABLED(CONFIG_DWC_MIPI_TC_DPHY_GEN3) // device_create_file(&pdev->dev, &dev_attr_idelay); #endif device_create_file(&pdev->dev, &dev_attr_len_config); device_create_file(&pdev->dev, &dev_attr_dw_dphy_g118_settle); return 0; } int dw_dphy_remove_capabilities_sysfs(struct platform_device *pdev) { device_remove_file(&pdev->dev, &dev_attr_dphy_reset); device_remove_file(&pdev->dev, &dev_attr_dphy_freq); device_remove_file(&pdev->dev, &dev_attr_dphy_addr); #if IS_ENABLED(CONFIG_DWC_MIPI_TC_DPHY_GEN3) // device_create_file(&pdev->dev, &dev_attr_idelay); #endif device_remove_file(&pdev->dev, &dev_attr_len_config); device_remove_file(&pdev->dev, &dev_attr_dw_dphy_g118_settle); return 0; }