2018-09-28 16:13:25 -03:00
// SPDX-License-Identifier: GPL-2.0+
2013-04-08 18:04:38 +02:00
/*
* i . MX drm driver - Television Encoder ( TVEv2 )
*
* Copyright ( C ) 2013 Philipp Zabel , Pengutronix
*/
# include <linux/clk-provider.h>
2019-07-16 08:42:18 +02:00
# include <linux/clk.h>
2013-11-03 11:23:34 +00:00
# include <linux/component.h>
2013-07-11 12:56:15 +01:00
# include <linux/i2c.h>
2019-07-16 08:42:18 +02:00
# include <linux/module.h>
# include <linux/platform_device.h>
2013-04-08 18:04:38 +02:00
# include <linux/regmap.h>
# include <linux/regulator/consumer.h>
# include <linux/spinlock.h>
# include <linux/videodev2.h>
2019-07-16 08:42:18 +02:00
# include <video/imx-ipu-v3.h>
2016-07-08 17:40:56 +08:00
# include <drm/drm_atomic_helper.h>
2013-04-08 18:04:38 +02:00
# include <drm/drm_fb_helper.h>
2019-01-17 22:03:34 +01:00
# include <drm/drm_probe_helper.h>
2013-04-08 18:04:38 +02:00
# include "imx-drm.h"
# define TVE_COM_CONF_REG 0x00
# define TVE_TVDAC0_CONT_REG 0x28
# define TVE_TVDAC1_CONT_REG 0x2c
# define TVE_TVDAC2_CONT_REG 0x30
# define TVE_CD_CONT_REG 0x34
# define TVE_INT_CONT_REG 0x64
# define TVE_STAT_REG 0x68
# define TVE_TST_MODE_REG 0x6c
# define TVE_MV_CONT_REG 0xdc
/* TVE_COM_CONF_REG */
# define TVE_SYNC_CH_2_EN BIT(22)
# define TVE_SYNC_CH_1_EN BIT(21)
# define TVE_SYNC_CH_0_EN BIT(20)
# define TVE_TV_OUT_MODE_MASK (0x7 << 12)
# define TVE_TV_OUT_DISABLE (0x0 << 12)
# define TVE_TV_OUT_CVBS_0 (0x1 << 12)
# define TVE_TV_OUT_CVBS_2 (0x2 << 12)
# define TVE_TV_OUT_CVBS_0_2 (0x3 << 12)
# define TVE_TV_OUT_SVIDEO_0_1 (0x4 << 12)
# define TVE_TV_OUT_SVIDEO_0_1_CVBS2_2 (0x5 << 12)
# define TVE_TV_OUT_YPBPR (0x6 << 12)
# define TVE_TV_OUT_RGB (0x7 << 12)
# define TVE_TV_STAND_MASK (0xf << 8)
# define TVE_TV_STAND_HD_1080P30 (0xc << 8)
# define TVE_P2I_CONV_EN BIT(7)
# define TVE_INP_VIDEO_FORM BIT(6)
# define TVE_INP_YCBCR_422 (0x0 << 6)
# define TVE_INP_YCBCR_444 (0x1 << 6)
# define TVE_DATA_SOURCE_MASK (0x3 << 4)
# define TVE_DATA_SOURCE_BUS1 (0x0 << 4)
# define TVE_DATA_SOURCE_BUS2 (0x1 << 4)
# define TVE_DATA_SOURCE_EXT (0x2 << 4)
# define TVE_DATA_SOURCE_TESTGEN (0x3 << 4)
# define TVE_IPU_CLK_EN_OFS 3
# define TVE_IPU_CLK_EN BIT(3)
# define TVE_DAC_SAMP_RATE_OFS 1
# define TVE_DAC_SAMP_RATE_WIDTH 2
# define TVE_DAC_SAMP_RATE_MASK (0x3 << 1)
# define TVE_DAC_FULL_RATE (0x0 << 1)
# define TVE_DAC_DIV2_RATE (0x1 << 1)
# define TVE_DAC_DIV4_RATE (0x2 << 1)
# define TVE_EN BIT(0)
/* TVE_TVDACx_CONT_REG */
# define TVE_TVDAC_GAIN_MASK (0x3f << 0)
/* TVE_CD_CONT_REG */
# define TVE_CD_CH_2_SM_EN BIT(22)
# define TVE_CD_CH_1_SM_EN BIT(21)
# define TVE_CD_CH_0_SM_EN BIT(20)
# define TVE_CD_CH_2_LM_EN BIT(18)
# define TVE_CD_CH_1_LM_EN BIT(17)
# define TVE_CD_CH_0_LM_EN BIT(16)
# define TVE_CD_CH_2_REF_LVL BIT(10)
# define TVE_CD_CH_1_REF_LVL BIT(9)
# define TVE_CD_CH_0_REF_LVL BIT(8)
# define TVE_CD_EN BIT(0)
/* TVE_INT_CONT_REG */
# define TVE_FRAME_END_IEN BIT(13)
# define TVE_CD_MON_END_IEN BIT(2)
# define TVE_CD_SM_IEN BIT(1)
# define TVE_CD_LM_IEN BIT(0)
/* TVE_TST_MODE_REG */
# define TVE_TVDAC_TEST_MODE_MASK (0x7 << 0)
2017-02-08 10:47:49 -02:00
# define IMX_TVE_DAC_VOLTAGE 2750000
2013-04-08 18:04:38 +02:00
enum {
TVE_MODE_TVOUT ,
TVE_MODE_VGA ,
} ;
struct imx_tve {
struct drm_connector connector ;
2016-07-06 14:49:24 +02:00
struct drm_encoder encoder ;
2013-04-08 18:04:38 +02:00
struct device * dev ;
spinlock_t lock ; /* register lock */
bool enabled ;
int mode ;
2016-07-06 14:49:24 +02:00
int di_hsync_pin ;
int di_vsync_pin ;
2013-04-08 18:04:38 +02:00
struct regmap * regmap ;
struct regulator * dac_reg ;
struct i2c_adapter * ddc ;
struct clk * clk ;
struct clk * di_sel_clk ;
struct clk_hw clk_hw_di ;
struct clk * di_clk ;
} ;
2016-07-06 15:47:11 +02:00
static inline struct imx_tve * con_to_tve ( struct drm_connector * c )
{
return container_of ( c , struct imx_tve , connector ) ;
}
2016-07-06 14:49:24 +02:00
static inline struct imx_tve * enc_to_tve ( struct drm_encoder * e )
{
return container_of ( e , struct imx_tve , encoder ) ;
}
2013-04-08 18:04:38 +02:00
static void tve_lock ( void * __tve )
2013-07-16 02:16:14 -03:00
__acquires ( & tve - > lock )
2013-04-08 18:04:38 +02:00
{
struct imx_tve * tve = __tve ;
2014-08-04 21:07:07 +02:00
2013-04-08 18:04:38 +02:00
spin_lock ( & tve - > lock ) ;
}
static void tve_unlock ( void * __tve )
2013-07-16 02:16:14 -03:00
__releases ( & tve - > lock )
2013-04-08 18:04:38 +02:00
{
struct imx_tve * tve = __tve ;
2014-08-04 21:07:07 +02:00
2013-04-08 18:04:38 +02:00
spin_unlock ( & tve - > lock ) ;
}
static void tve_enable ( struct imx_tve * tve )
{
if ( ! tve - > enabled ) {
2013-10-25 11:52:20 +03:00
tve - > enabled = true ;
2013-04-08 18:04:38 +02:00
clk_prepare_enable ( tve - > clk ) ;
2017-01-04 13:44:56 -02:00
regmap_update_bits ( tve - > regmap , TVE_COM_CONF_REG ,
TVE_EN , TVE_EN ) ;
2013-04-08 18:04:38 +02:00
}
/* clear interrupt status register */
regmap_write ( tve - > regmap , TVE_STAT_REG , 0xffffffff ) ;
/* cable detection irq disabled in VGA mode, enabled in TVOUT mode */
if ( tve - > mode = = TVE_MODE_VGA )
regmap_write ( tve - > regmap , TVE_INT_CONT_REG , 0 ) ;
else
regmap_write ( tve - > regmap , TVE_INT_CONT_REG ,
2013-08-11 17:20:23 +02:00
TVE_CD_SM_IEN |
TVE_CD_LM_IEN |
TVE_CD_MON_END_IEN ) ;
2013-04-08 18:04:38 +02:00
}
static void tve_disable ( struct imx_tve * tve )
{
if ( tve - > enabled ) {
2013-10-25 11:52:20 +03:00
tve - > enabled = false ;
2017-01-04 13:44:56 -02:00
regmap_update_bits ( tve - > regmap , TVE_COM_CONF_REG , TVE_EN , 0 ) ;
2013-04-08 18:04:38 +02:00
clk_disable_unprepare ( tve - > clk ) ;
}
}
static int tve_setup_tvout ( struct imx_tve * tve )
{
return - ENOTSUPP ;
}
static int tve_setup_vga ( struct imx_tve * tve )
{
unsigned int mask ;
unsigned int val ;
int ret ;
/* set gain to (1 + 10/128) to provide 0.7V peak-to-peak amplitude */
ret = regmap_update_bits ( tve - > regmap , TVE_TVDAC0_CONT_REG ,
TVE_TVDAC_GAIN_MASK , 0x0a ) ;
2015-01-20 20:44:07 -02:00
if ( ret )
return ret ;
2013-04-08 18:04:38 +02:00
ret = regmap_update_bits ( tve - > regmap , TVE_TVDAC1_CONT_REG ,
TVE_TVDAC_GAIN_MASK , 0x0a ) ;
2015-01-20 20:44:07 -02:00
if ( ret )
return ret ;
2013-04-08 18:04:38 +02:00
ret = regmap_update_bits ( tve - > regmap , TVE_TVDAC2_CONT_REG ,
TVE_TVDAC_GAIN_MASK , 0x0a ) ;
2015-01-20 20:44:07 -02:00
if ( ret )
return ret ;
2013-04-08 18:04:38 +02:00
/* set configuration register */
mask = TVE_DATA_SOURCE_MASK | TVE_INP_VIDEO_FORM ;
val = TVE_DATA_SOURCE_BUS2 | TVE_INP_YCBCR_444 ;
mask | = TVE_TV_STAND_MASK | TVE_P2I_CONV_EN ;
val | = TVE_TV_STAND_HD_1080P30 | 0 ;
mask | = TVE_TV_OUT_MODE_MASK | TVE_SYNC_CH_0_EN ;
val | = TVE_TV_OUT_RGB | TVE_SYNC_CH_0_EN ;
ret = regmap_update_bits ( tve - > regmap , TVE_COM_CONF_REG , mask , val ) ;
2015-01-20 20:44:07 -02:00
if ( ret )
2013-04-08 18:04:38 +02:00
return ret ;
/* set test mode (as documented) */
2015-01-20 20:44:07 -02:00
return regmap_update_bits ( tve - > regmap , TVE_TST_MODE_REG ,
2013-04-08 18:04:38 +02:00
TVE_TVDAC_TEST_MODE_MASK , 1 ) ;
}
static int imx_tve_connector_get_modes ( struct drm_connector * connector )
{
struct imx_tve * tve = con_to_tve ( connector ) ;
struct edid * edid ;
int ret = 0 ;
if ( ! tve - > ddc )
return 0 ;
edid = drm_get_edid ( connector , tve - > ddc ) ;
if ( edid ) {
2018-07-09 10:40:06 +02:00
drm_connector_update_edid_property ( connector , edid ) ;
2013-04-08 18:04:38 +02:00
ret = drm_add_edid_modes ( connector , edid ) ;
kfree ( edid ) ;
}
return ret ;
}
static int imx_tve_connector_mode_valid ( struct drm_connector * connector ,
struct drm_display_mode * mode )
{
struct imx_tve * tve = con_to_tve ( connector ) ;
unsigned long rate ;
2013-11-09 11:20:55 +00:00
2013-04-08 18:04:38 +02:00
/* pixel clock with 2x oversampling */
rate = clk_round_rate ( tve - > clk , 2000UL * mode - > clock ) / 2000 ;
if ( rate = = mode - > clock )
return MODE_OK ;
/* pixel clock without oversampling */
rate = clk_round_rate ( tve - > clk , 1000UL * mode - > clock ) / 1000 ;
if ( rate = = mode - > clock )
return MODE_OK ;
dev_warn ( tve - > dev , " ignoring mode %dx%d \n " ,
mode - > hdisplay , mode - > vdisplay ) ;
return MODE_BAD ;
}
static struct drm_encoder * imx_tve_connector_best_encoder (
struct drm_connector * connector )
{
struct imx_tve * tve = con_to_tve ( connector ) ;
2016-07-06 14:49:24 +02:00
return & tve - > encoder ;
2013-04-08 18:04:38 +02:00
}
static void imx_tve_encoder_mode_set ( struct drm_encoder * encoder ,
2014-12-18 18:00:24 -08:00
struct drm_display_mode * orig_mode ,
struct drm_display_mode * mode )
2013-04-08 18:04:38 +02:00
{
2016-07-06 14:49:24 +02:00
struct imx_tve * tve = enc_to_tve ( encoder ) ;
2013-04-08 18:04:38 +02:00
unsigned long rounded_rate ;
unsigned long rate ;
int div = 1 ;
int ret ;
/*
* FIXME
* we should try 4 k * mode - > clock first ,
* and enable 4 x oversampling for lower resolutions
*/
rate = 2000UL * mode - > clock ;
clk_set_rate ( tve - > clk , rate ) ;
rounded_rate = clk_get_rate ( tve - > clk ) ;
if ( rounded_rate > = rate )
div = 2 ;
clk_set_rate ( tve - > di_clk , rounded_rate / div ) ;
ret = clk_set_parent ( tve - > di_sel_clk , tve - > di_clk ) ;
if ( ret < 0 ) {
dev_err ( tve - > dev , " failed to set di_sel parent to tve_di: %d \n " ,
ret ) ;
}
2016-07-08 17:41:01 +08:00
regmap_update_bits ( tve - > regmap , TVE_COM_CONF_REG ,
TVE_IPU_CLK_EN , TVE_IPU_CLK_EN ) ;
2013-04-08 18:04:38 +02:00
if ( tve - > mode = = TVE_MODE_VGA )
2015-01-20 20:44:07 -02:00
ret = tve_setup_vga ( tve ) ;
2013-04-08 18:04:38 +02:00
else
2015-01-20 20:44:07 -02:00
ret = tve_setup_tvout ( tve ) ;
if ( ret )
dev_err ( tve - > dev , " failed to set configuration: %d \n " , ret ) ;
2013-04-08 18:04:38 +02:00
}
2016-07-08 17:41:01 +08:00
static void imx_tve_encoder_enable ( struct drm_encoder * encoder )
2013-04-08 18:04:38 +02:00
{
2016-07-06 14:49:24 +02:00
struct imx_tve * tve = enc_to_tve ( encoder ) ;
2013-04-08 18:04:38 +02:00
tve_enable ( tve ) ;
}
static void imx_tve_encoder_disable ( struct drm_encoder * encoder )
{
2016-07-06 14:49:24 +02:00
struct imx_tve * tve = enc_to_tve ( encoder ) ;
2013-04-08 18:04:38 +02:00
tve_disable ( tve ) ;
}
2016-07-06 14:49:24 +02:00
static int imx_tve_atomic_check ( struct drm_encoder * encoder ,
struct drm_crtc_state * crtc_state ,
struct drm_connector_state * conn_state )
{
struct imx_crtc_state * imx_crtc_state = to_imx_crtc_state ( crtc_state ) ;
struct imx_tve * tve = enc_to_tve ( encoder ) ;
imx_crtc_state - > bus_format = MEDIA_BUS_FMT_GBR888_1X24 ;
imx_crtc_state - > di_hsync_pin = tve - > di_hsync_pin ;
imx_crtc_state - > di_vsync_pin = tve - > di_vsync_pin ;
return 0 ;
}
2015-12-15 12:21:09 +01:00
static const struct drm_connector_funcs imx_tve_connector_funcs = {
2013-04-08 18:04:38 +02:00
. fill_modes = drm_helper_probe_single_connector_modes ,
2013-11-03 13:30:48 +00:00
. destroy = imx_drm_connector_destroy ,
2016-07-08 17:40:56 +08:00
. reset = drm_atomic_helper_connector_reset ,
. atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state ,
. atomic_destroy_state = drm_atomic_helper_connector_destroy_state ,
2013-04-08 18:04:38 +02:00
} ;
2015-12-15 12:21:09 +01:00
static const struct drm_connector_helper_funcs imx_tve_connector_helper_funcs = {
2013-04-08 18:04:38 +02:00
. get_modes = imx_tve_connector_get_modes ,
. best_encoder = imx_tve_connector_best_encoder ,
. mode_valid = imx_tve_connector_mode_valid ,
} ;
2015-12-15 12:21:09 +01:00
static const struct drm_encoder_funcs imx_tve_encoder_funcs = {
2013-11-03 13:30:48 +00:00
. destroy = imx_drm_encoder_destroy ,
2013-04-08 18:04:38 +02:00
} ;
2015-12-15 12:21:09 +01:00
static const struct drm_encoder_helper_funcs imx_tve_encoder_helper_funcs = {
2013-04-08 18:04:38 +02:00
. mode_set = imx_tve_encoder_mode_set ,
2016-07-08 17:41:01 +08:00
. enable = imx_tve_encoder_enable ,
2013-04-08 18:04:38 +02:00
. disable = imx_tve_encoder_disable ,
2016-07-06 14:49:24 +02:00
. atomic_check = imx_tve_atomic_check ,
2013-04-08 18:04:38 +02:00
} ;
static irqreturn_t imx_tve_irq_handler ( int irq , void * data )
{
struct imx_tve * tve = data ;
unsigned int val ;
regmap_read ( tve - > regmap , TVE_STAT_REG , & val ) ;
/* clear interrupt status register */
regmap_write ( tve - > regmap , TVE_STAT_REG , 0xffffffff ) ;
return IRQ_HANDLED ;
}
static unsigned long clk_tve_di_recalc_rate ( struct clk_hw * hw ,
unsigned long parent_rate )
{
struct imx_tve * tve = container_of ( hw , struct imx_tve , clk_hw_di ) ;
unsigned int val ;
int ret ;
ret = regmap_read ( tve - > regmap , TVE_COM_CONF_REG , & val ) ;
if ( ret < 0 )
return 0 ;
switch ( val & TVE_DAC_SAMP_RATE_MASK ) {
case TVE_DAC_DIV4_RATE :
return parent_rate / 4 ;
case TVE_DAC_DIV2_RATE :
return parent_rate / 2 ;
case TVE_DAC_FULL_RATE :
default :
return parent_rate ;
}
return 0 ;
}
static long clk_tve_di_round_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long * prate )
{
unsigned long div ;
div = * prate / rate ;
if ( div > = 4 )
return * prate / 4 ;
else if ( div > = 2 )
return * prate / 2 ;
2014-09-24 14:27:36 -07:00
return * prate ;
2013-04-08 18:04:38 +02:00
}
static int clk_tve_di_set_rate ( struct clk_hw * hw , unsigned long rate ,
unsigned long parent_rate )
{
struct imx_tve * tve = container_of ( hw , struct imx_tve , clk_hw_di ) ;
unsigned long div ;
u32 val ;
int ret ;
div = parent_rate / rate ;
if ( div > = 4 )
val = TVE_DAC_DIV4_RATE ;
else if ( div > = 2 )
val = TVE_DAC_DIV2_RATE ;
else
val = TVE_DAC_FULL_RATE ;
2013-08-11 17:20:23 +02:00
ret = regmap_update_bits ( tve - > regmap , TVE_COM_CONF_REG ,
TVE_DAC_SAMP_RATE_MASK , val ) ;
2013-04-08 18:04:38 +02:00
if ( ret < 0 ) {
dev_err ( tve - > dev , " failed to set divider: %d \n " , ret ) ;
return ret ;
}
return 0 ;
}
2018-10-27 07:47:41 +02:00
static const struct clk_ops clk_tve_di_ops = {
2013-04-08 18:04:38 +02:00
. round_rate = clk_tve_di_round_rate ,
. set_rate = clk_tve_di_set_rate ,
. recalc_rate = clk_tve_di_recalc_rate ,
} ;
static int tve_clk_init ( struct imx_tve * tve , void __iomem * base )
{
const char * tve_di_parent [ 1 ] ;
struct clk_init_data init = {
. name = " tve_di " ,
. ops = & clk_tve_di_ops ,
. num_parents = 1 ,
. flags = 0 ,
} ;
tve_di_parent [ 0 ] = __clk_get_name ( tve - > clk ) ;
init . parent_names = ( const char * * ) & tve_di_parent ;
tve - > clk_hw_di . init = & init ;
tve - > di_clk = clk_register ( tve - > dev , & tve - > clk_hw_di ) ;
if ( IS_ERR ( tve - > di_clk ) ) {
dev_err ( tve - > dev , " failed to register TVE output clock: %ld \n " ,
PTR_ERR ( tve - > di_clk ) ) ;
return PTR_ERR ( tve - > di_clk ) ;
}
return 0 ;
}
2013-11-03 13:30:48 +00:00
static int imx_tve_register ( struct drm_device * drm , struct imx_tve * tve )
2013-04-08 18:04:38 +02:00
{
2013-11-03 15:52:16 +00:00
int encoder_type ;
2013-04-08 18:04:38 +02:00
int ret ;
2013-11-03 15:52:16 +00:00
encoder_type = tve - > mode = = TVE_MODE_VGA ?
DRM_MODE_ENCODER_DAC : DRM_MODE_ENCODER_TVDAC ;
2016-07-06 14:49:24 +02:00
ret = imx_drm_encoder_parse_of ( drm , & tve - > encoder , tve - > dev - > of_node ) ;
2013-11-03 13:30:48 +00:00
if ( ret )
return ret ;
2013-04-08 18:04:38 +02:00
2016-07-06 14:49:24 +02:00
drm_encoder_helper_add ( & tve - > encoder , & imx_tve_encoder_helper_funcs ) ;
drm_encoder_init ( drm , & tve - > encoder , & imx_tve_encoder_funcs ,
drm: Pass 'name' to drm_encoder_init()
Done with coccinelle for the most part. However, it thinks '...' is
part of the semantic patch, so I put an 'int DOTDOTDOT' placeholder
in its place and got rid of it with sed afterwards.
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
)
{ ... }
@@
identifier dev, encoder, funcs;
@@
int drm_encoder_init(struct drm_device *dev,
struct drm_encoder *encoder,
const struct drm_encoder_funcs *funcs,
int encoder_type
+ ,const char *name, int DOTDOTDOT
);
@@
expression E1, E2, E3, E4;
@@
drm_encoder_init(E1, E2, E3, E4
+ ,NULL
)
v2: Add ', or NULL...' to @name kernel doc (Jani)
Annotate the function with __printf() attribute (Jani)
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
Signed-off-by: Daniel Vetter <daniel.vetter@ffwll.ch>
Link: http://patchwork.freedesktop.org/patch/msgid/1449670818-2966-1-git-send-email-ville.syrjala@linux.intel.com
2015-12-09 16:20:18 +02:00
encoder_type , NULL ) ;
2013-04-08 18:04:38 +02:00
drm_connector_helper_add ( & tve - > connector ,
& imx_tve_connector_helper_funcs ) ;
2019-07-26 19:23:05 +02:00
drm_connector_init_with_ddc ( drm , & tve - > connector ,
& imx_tve_connector_funcs ,
DRM_MODE_CONNECTOR_VGA ,
tve - > ddc ) ;
2013-04-08 18:04:38 +02:00
2018-07-09 10:40:07 +02:00
drm_connector_attach_encoder ( & tve - > connector , & tve - > encoder ) ;
2013-04-08 18:04:38 +02:00
return 0 ;
}
static bool imx_tve_readable_reg ( struct device * dev , unsigned int reg )
{
return ( reg % 4 = = 0 ) & & ( reg < = 0xdc ) ;
}
static struct regmap_config tve_regmap_config = {
. reg_bits = 32 ,
. val_bits = 32 ,
. reg_stride = 4 ,
. readable_reg = imx_tve_readable_reg ,
. lock = tve_lock ,
. unlock = tve_unlock ,
. max_register = 0xdc ,
} ;
2014-09-27 16:16:02 +03:00
static const char * const imx_tve_modes [ ] = {
2013-04-08 18:04:38 +02:00
[ TVE_MODE_TVOUT ] = " tvout " ,
[ TVE_MODE_VGA ] = " vga " ,
} ;
2013-12-24 10:17:44 +08:00
static const int of_get_tve_mode ( struct device_node * np )
2013-04-08 18:04:38 +02:00
{
const char * bm ;
int ret , i ;
ret = of_property_read_string ( np , " fsl,tve-mode " , & bm ) ;
if ( ret < 0 )
return ret ;
for ( i = 0 ; i < ARRAY_SIZE ( imx_tve_modes ) ; i + + )
if ( ! strcasecmp ( bm , imx_tve_modes [ i ] ) )
return i ;
return - EINVAL ;
}
2013-11-03 11:23:34 +00:00
static int imx_tve_bind ( struct device * dev , struct device * master , void * data )
2013-04-08 18:04:38 +02:00
{
2013-11-03 11:23:34 +00:00
struct platform_device * pdev = to_platform_device ( dev ) ;
2013-11-03 13:30:48 +00:00
struct drm_device * drm = data ;
2013-11-03 11:23:34 +00:00
struct device_node * np = dev - > of_node ;
2013-04-08 18:04:38 +02:00
struct device_node * ddc_node ;
struct imx_tve * tve ;
struct resource * res ;
void __iomem * base ;
unsigned int val ;
int irq ;
int ret ;
2013-11-03 11:23:34 +00:00
tve = devm_kzalloc ( dev , sizeof ( * tve ) , GFP_KERNEL ) ;
2013-04-08 18:04:38 +02:00
if ( ! tve )
return - ENOMEM ;
2013-11-03 11:23:34 +00:00
tve - > dev = dev ;
2013-04-08 18:04:38 +02:00
spin_lock_init ( & tve - > lock ) ;
2014-04-10 14:19:05 +08:00
ddc_node = of_parse_phandle ( np , " ddc-i2c-bus " , 0 ) ;
2013-04-08 18:04:38 +02:00
if ( ddc_node ) {
tve - > ddc = of_find_i2c_adapter_by_node ( ddc_node ) ;
of_node_put ( ddc_node ) ;
}
tve - > mode = of_get_tve_mode ( np ) ;
if ( tve - > mode ! = TVE_MODE_VGA ) {
2013-11-03 11:23:34 +00:00
dev_err ( dev , " only VGA mode supported, currently \n " ) ;
2013-04-08 18:04:38 +02:00
return - EINVAL ;
}
if ( tve - > mode = = TVE_MODE_VGA ) {
2013-08-11 17:20:23 +02:00
ret = of_property_read_u32 ( np , " fsl,hsync-pin " ,
2016-07-06 14:49:24 +02:00
& tve - > di_hsync_pin ) ;
2013-08-11 17:20:23 +02:00
2013-04-08 18:04:38 +02:00
if ( ret < 0 ) {
2016-07-09 18:57:44 -03:00
dev_err ( dev , " failed to get hsync pin \n " ) ;
2013-04-08 18:04:38 +02:00
return ret ;
}
2016-07-09 18:57:43 -03:00
ret = of_property_read_u32 ( np , " fsl,vsync-pin " ,
& tve - > di_vsync_pin ) ;
2013-08-11 17:20:23 +02:00
2013-04-08 18:04:38 +02:00
if ( ret < 0 ) {
2013-11-03 11:23:34 +00:00
dev_err ( dev , " failed to get vsync pin \n " ) ;
2013-04-08 18:04:38 +02:00
return ret ;
}
}
res = platform_get_resource ( pdev , IORESOURCE_MEM , 0 ) ;
2013-11-03 11:23:34 +00:00
base = devm_ioremap_resource ( dev , res ) ;
2013-05-02 13:41:41 +02:00
if ( IS_ERR ( base ) )
return PTR_ERR ( base ) ;
2013-04-08 18:04:38 +02:00
tve_regmap_config . lock_arg = tve ;
2013-11-03 11:23:34 +00:00
tve - > regmap = devm_regmap_init_mmio_clk ( dev , " tve " , base ,
2013-04-08 18:04:38 +02:00
& tve_regmap_config ) ;
if ( IS_ERR ( tve - > regmap ) ) {
2013-11-03 11:23:34 +00:00
dev_err ( dev , " failed to init regmap: %ld \n " ,
2013-04-08 18:04:38 +02:00
PTR_ERR ( tve - > regmap ) ) ;
return PTR_ERR ( tve - > regmap ) ;
}
irq = platform_get_irq ( pdev , 0 ) ;
if ( irq < 0 ) {
2013-11-03 11:23:34 +00:00
dev_err ( dev , " failed to get irq \n " ) ;
2013-04-08 18:04:38 +02:00
return irq ;
}
2013-11-03 11:23:34 +00:00
ret = devm_request_threaded_irq ( dev , irq , NULL ,
2013-04-08 18:04:38 +02:00
imx_tve_irq_handler , IRQF_ONESHOT ,
" imx-tve " , tve ) ;
if ( ret < 0 ) {
2013-11-03 11:23:34 +00:00
dev_err ( dev , " failed to request irq: %d \n " , ret ) ;
2013-04-08 18:04:38 +02:00
return ret ;
}
2013-11-03 11:23:34 +00:00
tve - > dac_reg = devm_regulator_get ( dev , " dac " ) ;
2013-04-08 18:04:38 +02:00
if ( ! IS_ERR ( tve - > dac_reg ) ) {
2017-02-08 10:47:49 -02:00
if ( regulator_get_voltage ( tve - > dac_reg ) ! = IMX_TVE_DAC_VOLTAGE )
dev_warn ( dev , " dac voltage is not %d uV \n " , IMX_TVE_DAC_VOLTAGE ) ;
2013-05-21 11:24:44 -03:00
ret = regulator_enable ( tve - > dac_reg ) ;
if ( ret )
return ret ;
2013-04-08 18:04:38 +02:00
}
2013-11-03 11:23:34 +00:00
tve - > clk = devm_clk_get ( dev , " tve " ) ;
2013-04-08 18:04:38 +02:00
if ( IS_ERR ( tve - > clk ) ) {
2013-11-03 11:23:34 +00:00
dev_err ( dev , " failed to get high speed tve clock: %ld \n " ,
2013-04-08 18:04:38 +02:00
PTR_ERR ( tve - > clk ) ) ;
return PTR_ERR ( tve - > clk ) ;
}
/* this is the IPU DI clock input selector, can be parented to tve_di */
2013-11-03 11:23:34 +00:00
tve - > di_sel_clk = devm_clk_get ( dev , " di_sel " ) ;
2013-04-08 18:04:38 +02:00
if ( IS_ERR ( tve - > di_sel_clk ) ) {
2013-11-03 11:23:34 +00:00
dev_err ( dev , " failed to get ipu di mux clock: %ld \n " ,
2013-04-08 18:04:38 +02:00
PTR_ERR ( tve - > di_sel_clk ) ) ;
return PTR_ERR ( tve - > di_sel_clk ) ;
}
ret = tve_clk_init ( tve , base ) ;
if ( ret < 0 )
return ret ;
ret = regmap_read ( tve - > regmap , TVE_COM_CONF_REG , & val ) ;
if ( ret < 0 ) {
2014-10-09 20:29:32 +02:00
dev_err ( dev , " failed to read configuration register: %d \n " ,
ret ) ;
2013-04-08 18:04:38 +02:00
return ret ;
}
if ( val ! = 0x00100000 ) {
2013-11-03 11:23:34 +00:00
dev_err ( dev , " configuration register default value indicates this is not a TVEv2 \n " ) ;
2013-04-08 18:04:38 +02:00
return - ENODEV ;
2013-10-10 16:07:59 -07:00
}
2013-04-08 18:04:38 +02:00
/* disable cable detection for VGA mode */
ret = regmap_write ( tve - > regmap , TVE_CD_CONT_REG , 0 ) ;
2015-01-20 20:44:07 -02:00
if ( ret )
return ret ;
2013-04-08 18:04:38 +02:00
2013-11-03 13:30:48 +00:00
ret = imx_tve_register ( drm , tve ) ;
2013-04-08 18:04:38 +02:00
if ( ret )
return ret ;
2013-11-03 11:23:34 +00:00
dev_set_drvdata ( dev , tve ) ;
2013-04-08 18:04:38 +02:00
return 0 ;
}
2013-11-03 11:23:34 +00:00
static void imx_tve_unbind ( struct device * dev , struct device * master ,
void * data )
2013-04-08 18:04:38 +02:00
{
2013-11-03 11:23:34 +00:00
struct imx_tve * tve = dev_get_drvdata ( dev ) ;
2013-04-08 18:04:38 +02:00
if ( ! IS_ERR ( tve - > dac_reg ) )
regulator_disable ( tve - > dac_reg ) ;
2013-11-03 11:23:34 +00:00
}
2013-04-08 18:04:38 +02:00
2013-11-03 11:23:34 +00:00
static const struct component_ops imx_tve_ops = {
. bind = imx_tve_bind ,
. unbind = imx_tve_unbind ,
} ;
static int imx_tve_probe ( struct platform_device * pdev )
{
return component_add ( & pdev - > dev , & imx_tve_ops ) ;
}
static int imx_tve_remove ( struct platform_device * pdev )
{
component_del ( & pdev - > dev , & imx_tve_ops ) ;
2013-04-08 18:04:38 +02:00
return 0 ;
}
static const struct of_device_id imx_tve_dt_ids [ ] = {
{ . compatible = " fsl,imx53-tve " , } ,
{ /* sentinel */ }
} ;
2015-11-30 15:02:44 +00:00
MODULE_DEVICE_TABLE ( of , imx_tve_dt_ids ) ;
2013-04-08 18:04:38 +02:00
static struct platform_driver imx_tve_driver = {
. probe = imx_tve_probe ,
. remove = imx_tve_remove ,
. driver = {
. of_match_table = imx_tve_dt_ids ,
. name = " imx-tve " ,
} ,
} ;
module_platform_driver ( imx_tve_driver ) ;
MODULE_DESCRIPTION ( " i.MX Television Encoder driver " ) ;
MODULE_AUTHOR ( " Philipp Zabel, Pengutronix " ) ;
MODULE_LICENSE ( " GPL " ) ;
2013-08-18 21:40:04 -03:00
MODULE_ALIAS ( " platform:imx-tve " ) ;