static ssize_t sysfs_write_fps(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret, fps; struct fb_info *fbi = dev_get_drvdata(dev); struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par; struct attr_info *attr_info = fb_dev->priv1; struct panel_spec* panel = fb_dev->panel; if (!panel) { pr_err("panel doesn't exist."); return -ENXIO; } ret = kstrtoint(buf, 10, &fps); fps = fps > 0 ? fps : attr_info->origin_fps; if (panel->fps == fps) { /* Do nothing */ pr_warn("new fps is the same as current fps\n"); return count; } ret = sprdfb_chg_clk_intf(fb_dev, SPRDFB_DYNAMIC_FPS, (u32)fps); if (ret) { pr_err("%s: failed to change dpi clock. ret=%d\n", __func__, ret); return ret; } attr_info->curr_fps = fps; return count; }
static ssize_t sysfs_write_mipi_clk(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret = 0; u32 dphy_freq; struct fb_info *fbi = dev_get_drvdata(dev); struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par; struct attr_info *attr_info = fb_dev->priv1; struct panel_spec* panel = fb_dev->panel; if (!panel) { pr_err("panel doesn't exist."); return -ENXIO; } if (panel->type != LCD_MODE_DSI) { pr_err("sys write failure. Current panel is not mipi dsi\n"); return count; } ret = kstrtoint(buf, 10, &dphy_freq); if (ret) { pr_err("Invalid input for dphy_freq\n"); return -EINVAL; } if (dphy_freq > 0) { /* * because of double edge trigger, * the rule is actual freq * 10 / 2, * Eg: Required freq is 500M * Equation: 2500*2*1000/10=500*1000=2500*200=500M */ dphy_freq *= 200; } else dphy_freq = attr_info->origin_mipi_clk; /* dphy supported freq ranges is 90M-1500M*/ pr_debug("input dphy_freq is %d\n", dphy_freq); if (dphy_freq == attr_info->curr_mipi_clk) { /* Do nothing */ pr_warn("new dphy_freq is the same as current freq\n"); return count; } if (dphy_freq <= 1500000 && dphy_freq >= 90000) { ret = sprdfb_chg_clk_intf(fb_dev, SPRDFB_DYNAMIC_MIPI_CLK, dphy_freq); if (ret) { pr_err("sprdfb_chg_clk_intf change d-phy freq fail.\n"); return count; } attr_info->curr_mipi_clk = dphy_freq; } else { pr_warn("input mipi frequency:%d is out of range.\n", dphy_freq); } return count; }
static ssize_t sysfs_write_pclk(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) { int ret; int divider; u32 dpi_clk_src, new_pclk; struct fb_info *fbi = dev_get_drvdata(dev); struct sprdfb_device *fb_dev = (struct sprdfb_device *)fbi->par; struct attr_info *attr_info = fb_dev->priv1; sscanf(buf, "%u,%d\n", &dpi_clk_src, ÷r); if (divider == 0 && dpi_clk_src == 0) { new_pclk = attr_info->origin_pclk; goto DIRECT_GO; } if (divider < 1 || divider > 0xff || dpi_clk_src < 1) { pr_err("divider:[%d], clk_src:[%d] is invalid\n", divider, dpi_clk_src); return count; } if (dpi_clk_src < 1000) dpi_clk_src *= 1000000; /* MHz */ new_pclk = dpi_clk_src / divider; DIRECT_GO: if (new_pclk == fb_dev->dpi_clock) { /* Do nothing */ pr_warn("new pclk is the same as current pclk\n"); return count; } ret = sprdfb_chg_clk_intf(fb_dev, SPRDFB_DYNAMIC_PCLK, new_pclk); if (ret) { pr_err("%s: failed to change dpi clock. ret=%d\n", __func__, ret); return ret; } attr_info->curr_pclk = new_pclk; return count; }
static int sprdfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg) { int result = -1; struct sprdfb_device *dev = NULL; #ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT overlay_info local_overlay_info; overlay_display local_overlay_display; #endif int power_mode; void __user *argp = (void __user *)arg; if(NULL == info){ printk(KERN_ERR "sprdfb: sprdfb_ioctl error. (Invalid Parameter)"); return -1; } dev = info->par; switch(cmd){ #ifdef CONFIG_FB_LCD_OVERLAY_SUPPORT case SPRD_FB_SET_OVERLAY: pr_debug(KERN_INFO "sprdfb: [%s]: SPRD_FB_SET_OVERLAY\n", __FUNCTION__); memset(&local_overlay_info,0,sizeof(local_overlay_info)); if (copy_from_user(&local_overlay_info, argp, sizeof(local_overlay_info))){ printk("sprdfb: SET_OVERLAY copy failed!\n"); return -EFAULT; } if(NULL != dev->ctrl->enable_overlay){ result = dev->ctrl->enable_overlay(dev, &local_overlay_info, 1); } break; case SPRD_FB_DISPLAY_OVERLAY: pr_debug(KERN_INFO "sprdfb: [%s]: SPRD_FB_DISPLAY_OVERLAY\n", __FUNCTION__); memset(&local_overlay_display,0,sizeof(local_overlay_display)); if (copy_from_user(&local_overlay_display, argp, sizeof(local_overlay_display))){ printk("sprdfb: DISPLAY_OVERLAY copy failed!\n"); return -EFAULT; } if(NULL != dev->ctrl->display_overlay){ result = dev->ctrl->display_overlay(dev, &local_overlay_display); } break; #endif #ifdef CONFIG_FB_VSYNC_SUPPORT case FBIO_WAITFORVSYNC: pr_debug(KERN_INFO "sprdfb: [%s]: FBIO_WAITFORVSYNC\n", __FUNCTION__); if(NULL != dev->ctrl->wait_for_vsync){ result = dev->ctrl->wait_for_vsync(dev); } break; #endif #ifdef CONFIG_FB_DYNAMIC_FREQ_SCALING case SPRD_FB_CHANGE_FPS: { int fps; result = copy_from_user(&fps, argp, sizeof(fps)); if (result) { pr_err("%s: copy_from_user failed", __func__); return result; } pr_info("%s: fps will be changed to %d via ioctl\n", __func__, fps); result = sprdfb_chg_clk_intf(dev, SPRDFB_DYNAMIC_FPS, fps); if (result) { pr_err("%s: fps is set fail. fps=%d, ret=%d\n", __func__, fps, result); return result; } break; } #endif case SPRD_FB_IS_REFRESH_DONE: pr_debug(KERN_INFO "sprdfb: [%s]: SPRD_FB_IS_REFRESH_DONE\n", __FUNCTION__); if(NULL != dev->ctrl->is_refresh_done){ result = dev->ctrl->is_refresh_done(dev); } break; case SPRD_FB_SET_POWER_MODE: result = copy_from_user(&power_mode, argp, sizeof(power_mode)); printk("sprdfb: [%s] : SPRD_FB_SET_POWER_MODE (%d)\n", __FUNCTION__, power_mode); break; default: printk(KERN_INFO "sprdfb: [%s]: unknown cmd(%d)\n", __FUNCTION__, cmd); break; } pr_debug(KERN_INFO "sprdfb: [%s]: return %d\n",__FUNCTION__, result); return result; }