Commit f1f60b5f authored by Laurent Pinchart's avatar Laurent Pinchart

fbdev: sh_mobile_lcdc: Reorder code into sections

Make the driver more readable by reordering code and splitting it into
logical sections. Reorder the headers alphabetically.

No modification to the code have been performed.
Signed-off-by: default avatarLaurent Pinchart <laurent.pinchart@ideasonboard.com>
parent c2bc0a75
......@@ -8,26 +8,27 @@
* for more details.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/mm.h>
#include <linux/atomic.h>
#include <linux/backlight.h>
#include <linux/clk.h>
#include <linux/pm_runtime.h>
#include <linux/platform_device.h>
#include <linux/console.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/ioctl.h>
#include <linux/slab.h>
#include <linux/console.h>
#include <linux/backlight.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <video/sh_mobile_lcdc.h>
#include <video/sh_mobile_meram.h>
#include <linux/atomic.h>
#include "sh_mobile_lcdcfb.h"
......@@ -37,6 +38,24 @@
#define MAX_XRES 1920
#define MAX_YRES 1080
struct sh_mobile_lcdc_priv {
void __iomem *base;
int irq;
atomic_t hw_usecnt;
struct device *dev;
struct clk *dot_clk;
unsigned long lddckr;
struct sh_mobile_lcdc_chan ch[2];
struct notifier_block notifier;
int started;
int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
struct sh_mobile_meram_info *meram_dev;
};
/* -----------------------------------------------------------------------------
* Registers access
*/
static unsigned long lcdc_offs_mainlcd[NR_CH_REGS] = {
[LDDCKPAT1R] = 0x400,
[LDDCKPAT2R] = 0x404,
......@@ -75,38 +94,6 @@ static unsigned long lcdc_offs_sublcd[NR_CH_REGS] = {
[LDPMR] = 0x63c,
};
static const struct fb_videomode default_720p = {
.name = "HDMI 720p",
.xres = 1280,
.yres = 720,
.left_margin = 220,
.right_margin = 110,
.hsync_len = 40,
.upper_margin = 20,
.lower_margin = 5,
.vsync_len = 5,
.pixclock = 13468,
.refresh = 60,
.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
};
struct sh_mobile_lcdc_priv {
void __iomem *base;
int irq;
atomic_t hw_usecnt;
struct device *dev;
struct clk *dot_clk;
unsigned long lddckr;
struct sh_mobile_lcdc_chan ch[2];
struct notifier_block notifier;
int started;
int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
struct sh_mobile_meram_info *meram_dev;
};
static bool banked(int reg_nr)
{
switch (reg_nr) {
......@@ -127,6 +114,11 @@ static bool banked(int reg_nr)
return false;
}
static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
{
return chan->cfg.chan == LCDC_CHAN_SUBLCD;
}
static void lcdc_write_chan(struct sh_mobile_lcdc_chan *chan,
int reg_nr, unsigned long data)
{
......@@ -169,11 +161,77 @@ static void lcdc_wait_bit(struct sh_mobile_lcdc_priv *priv,
cpu_relax();
}
static int lcdc_chan_is_sublcd(struct sh_mobile_lcdc_chan *chan)
/* -----------------------------------------------------------------------------
* Clock management
*/
static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
{
return chan->cfg.chan == LCDC_CHAN_SUBLCD;
if (atomic_inc_and_test(&priv->hw_usecnt)) {
if (priv->dot_clk)
clk_enable(priv->dot_clk);
pm_runtime_get_sync(priv->dev);
if (priv->meram_dev && priv->meram_dev->pdev)
pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
}
}
static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
{
if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
if (priv->meram_dev && priv->meram_dev->pdev)
pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
pm_runtime_put(priv->dev);
if (priv->dot_clk)
clk_disable(priv->dot_clk);
}
}
static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
int clock_source,
struct sh_mobile_lcdc_priv *priv)
{
char *str;
switch (clock_source) {
case LCDC_CLK_BUS:
str = "bus_clk";
priv->lddckr = LDDCKR_ICKSEL_BUS;
break;
case LCDC_CLK_PERIPHERAL:
str = "peripheral_clk";
priv->lddckr = LDDCKR_ICKSEL_MIPI;
break;
case LCDC_CLK_EXTERNAL:
str = NULL;
priv->lddckr = LDDCKR_ICKSEL_HDMI;
break;
default:
return -EINVAL;
}
if (str) {
priv->dot_clk = clk_get(&pdev->dev, str);
if (IS_ERR(priv->dot_clk)) {
dev_err(&pdev->dev, "cannot get dot clock %s\n", str);
return PTR_ERR(priv->dot_clk);
}
}
/* Runtime PM support involves two step for this driver:
* 1) Enable Runtime PM
* 2) Force Runtime PM Resume since hardware is accessed from probe()
*/
priv->dev = &pdev->dev;
pm_runtime_enable(priv->dev);
pm_runtime_resume(priv->dev);
return 0;
}
/* -----------------------------------------------------------------------------
* Sys panel and deferred I/O
*/
static void lcdc_sys_write_index(void *handle, unsigned long data)
{
struct sh_mobile_lcdc_chan *ch = handle;
......@@ -216,69 +274,6 @@ struct sh_mobile_lcdc_sys_bus_ops sh_mobile_lcdc_sys_bus_ops = {
lcdc_sys_read_data,
};
static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
{
if (var->grayscale > 1)
return var->grayscale;
switch (var->bits_per_pixel) {
case 16:
return V4L2_PIX_FMT_RGB565;
case 24:
return V4L2_PIX_FMT_BGR24;
case 32:
return V4L2_PIX_FMT_BGR32;
default:
return 0;
}
}
static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
{
return var->grayscale > 1;
}
static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
{
if (var->grayscale <= 1)
return false;
switch (var->grayscale) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_NV24:
case V4L2_PIX_FMT_NV42:
return true;
default:
return false;
}
}
static void sh_mobile_lcdc_clk_on(struct sh_mobile_lcdc_priv *priv)
{
if (atomic_inc_and_test(&priv->hw_usecnt)) {
if (priv->dot_clk)
clk_enable(priv->dot_clk);
pm_runtime_get_sync(priv->dev);
if (priv->meram_dev && priv->meram_dev->pdev)
pm_runtime_get_sync(&priv->meram_dev->pdev->dev);
}
}
static void sh_mobile_lcdc_clk_off(struct sh_mobile_lcdc_priv *priv)
{
if (atomic_sub_return(1, &priv->hw_usecnt) == -1) {
if (priv->meram_dev && priv->meram_dev->pdev)
pm_runtime_put_sync(&priv->meram_dev->pdev->dev);
pm_runtime_put(priv->dev);
if (priv->dot_clk)
clk_disable(priv->dot_clk);
}
}
static int sh_mobile_lcdc_sginit(struct fb_info *info,
struct list_head *pagelist)
{
......@@ -345,6 +340,55 @@ static void sh_mobile_lcdc_deferred_io_touch(struct fb_info *info)
schedule_delayed_work(&info->deferred_work, fbdefio->delay);
}
/* -----------------------------------------------------------------------------
* Format helpers
*/
static int sh_mobile_format_fourcc(const struct fb_var_screeninfo *var)
{
if (var->grayscale > 1)
return var->grayscale;
switch (var->bits_per_pixel) {
case 16:
return V4L2_PIX_FMT_RGB565;
case 24:
return V4L2_PIX_FMT_BGR24;
case 32:
return V4L2_PIX_FMT_BGR32;
default:
return 0;
}
}
static int sh_mobile_format_is_fourcc(const struct fb_var_screeninfo *var)
{
return var->grayscale > 1;
}
static bool sh_mobile_format_is_yuv(const struct fb_var_screeninfo *var)
{
if (var->grayscale <= 1)
return false;
switch (var->grayscale) {
case V4L2_PIX_FMT_NV12:
case V4L2_PIX_FMT_NV21:
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
case V4L2_PIX_FMT_NV24:
case V4L2_PIX_FMT_NV42:
return true;
default:
return false;
}
}
/* -----------------------------------------------------------------------------
* Start, stop and IRQ
*/
static irqreturn_t sh_mobile_lcdc_irq(int irq, void *data)
{
struct sh_mobile_lcdc_priv *priv = data;
......@@ -790,86 +834,9 @@ static void sh_mobile_lcdc_stop(struct sh_mobile_lcdc_priv *priv)
sh_mobile_lcdc_clk_off(priv);
}
static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
{
int interface_type = ch->cfg.interface_type;
switch (interface_type) {
case RGB8:
case RGB9:
case RGB12A:
case RGB12B:
case RGB16:
case RGB18:
case RGB24:
case SYS8A:
case SYS8B:
case SYS8C:
case SYS8D:
case SYS9:
case SYS12:
case SYS16A:
case SYS16B:
case SYS16C:
case SYS18:
case SYS24:
break;
default:
return -EINVAL;
}
/* SUBLCD only supports SYS interface */
if (lcdc_chan_is_sublcd(ch)) {
if (!(interface_type & LDMT1R_IFM))
return -EINVAL;
interface_type &= ~LDMT1R_IFM;
}
ch->ldmt1r_value = interface_type;
return 0;
}
static int sh_mobile_lcdc_setup_clocks(struct platform_device *pdev,
int clock_source,
struct sh_mobile_lcdc_priv *priv)
{
char *str;
switch (clock_source) {
case LCDC_CLK_BUS:
str = "bus_clk";
priv->lddckr = LDDCKR_ICKSEL_BUS;
break;
case LCDC_CLK_PERIPHERAL:
str = "peripheral_clk";
priv->lddckr = LDDCKR_ICKSEL_MIPI;
break;
case LCDC_CLK_EXTERNAL:
str = NULL;
priv->lddckr = LDDCKR_ICKSEL_HDMI;
break;
default:
return -EINVAL;
}
if (str) {
priv->dot_clk = clk_get(&pdev->dev, str);
if (IS_ERR(priv->dot_clk)) {
dev_err(&pdev->dev, "cannot get dot clock %s\n", str);
return PTR_ERR(priv->dot_clk);
}
}
/* Runtime PM support involves two step for this driver:
* 1) Enable Runtime PM
* 2) Force Runtime PM Resume since hardware is accessed from probe()
*/
priv->dev = &pdev->dev;
pm_runtime_enable(priv->dev);
pm_runtime_resume(priv->dev);
return 0;
}
/* -----------------------------------------------------------------------------
* Frame buffer operations
*/
static int sh_mobile_lcdc_setcolreg(u_int regno,
u_int red, u_int green, u_int blue,
......@@ -1334,6 +1301,10 @@ static struct fb_ops sh_mobile_lcdc_ops = {
.fb_set_par = sh_mobile_set_par,
};
/* -----------------------------------------------------------------------------
* Backlight
*/
static int sh_mobile_lcdc_update_bl(struct backlight_device *bdev)
{
struct sh_mobile_lcdc_chan *ch = bl_get_data(bdev);
......@@ -1393,6 +1364,10 @@ static void sh_mobile_lcdc_bl_remove(struct backlight_device *bdev)
backlight_device_unregister(bdev);
}
/* -----------------------------------------------------------------------------
* Power management
*/
static int sh_mobile_lcdc_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
......@@ -1436,6 +1411,10 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
.runtime_resume = sh_mobile_lcdc_runtime_resume,
};
/* -----------------------------------------------------------------------------
* Framebuffer notifier
*/
/* locking: called with info->lock held */
static int sh_mobile_lcdc_notify(struct notifier_block *nb,
unsigned long action, void *data)
......@@ -1476,6 +1455,28 @@ static int sh_mobile_lcdc_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
/* -----------------------------------------------------------------------------
* Probe/remove and driver init/exit
*/
static const struct fb_videomode default_720p = {
.name = "HDMI 720p",
.xres = 1280,
.yres = 720,
.left_margin = 220,
.right_margin = 110,
.hsync_len = 40,
.upper_margin = 20,
.lower_margin = 5,
.vsync_len = 5,
.pixclock = 13468,
.refresh = 60,
.sync = FB_SYNC_VERT_HIGH_ACT | FB_SYNC_HOR_HIGH_ACT,
};
static int sh_mobile_lcdc_remove(struct platform_device *pdev)
{
struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
......@@ -1527,6 +1528,46 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
return 0;
}
static int sh_mobile_lcdc_check_interface(struct sh_mobile_lcdc_chan *ch)
{
int interface_type = ch->cfg.interface_type;
switch (interface_type) {
case RGB8:
case RGB9:
case RGB12A:
case RGB12B:
case RGB16:
case RGB18:
case RGB24:
case SYS8A:
case SYS8B:
case SYS8C:
case SYS8D:
case SYS9:
case SYS12:
case SYS16A:
case SYS16B:
case SYS16C:
case SYS18:
case SYS24:
break;
default:
return -EINVAL;
}
/* SUBLCD only supports SYS interface */
if (lcdc_chan_is_sublcd(ch)) {
if (!(interface_type & LDMT1R_IFM))
return -EINVAL;
interface_type &= ~LDMT1R_IFM;
}
ch->ldmt1r_value = interface_type;
return 0;
}
static int __devinit sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch,
struct device *dev)
{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment