2012-03-08 16:02:20 +00:00
/**************************************************************************
* Copyright ( c ) 2011 , Intel Corporation .
* All Rights Reserved .
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms and conditions of the GNU General Public License ,
* version 2 , as published by the Free Software Foundation .
*
* This program is distributed in the hope it will be useful , but WITHOUT
* ANY WARRANTY ; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE . See the GNU General Public License for
* more details .
*
* You should have received a copy of the GNU General Public License along with
* this program ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin St - Fifth Floor , Boston , MA 02110 - 1301 USA .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "psb_drv.h"
# include "mid_bios.h"
# include "mdfld_output.h"
# include "mdfld_dsi_output.h"
# include "tc35876x-dsi-lvds.h"
# include <asm/intel_scu_ipc.h>
# ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
# define MRST_BLC_MAX_PWM_REG_FREQ 0xFFFF
# define BLC_PWM_PRECISION_FACTOR 100 /* 10000000 */
# define BLC_PWM_FREQ_CALC_CONSTANT 32
# define MHz 1000000
# define BRIGHTNESS_MIN_LEVEL 1
# define BRIGHTNESS_MAX_LEVEL 100
# define BRIGHTNESS_MASK 0xFF
# define BLC_POLARITY_NORMAL 0
# define BLC_POLARITY_INVERSE 1
# define BLC_ADJUSTMENT_MAX 100
# define MDFLD_BLC_PWM_PRECISION_FACTOR 10
# define MDFLD_BLC_MAX_PWM_REG_FREQ 0xFFFE
# define MDFLD_BLC_MIN_PWM_REG_FREQ 0x2
# define MDFLD_BACKLIGHT_PWM_POLARITY_BIT_CLEAR (0xFFFE)
# define MDFLD_BACKLIGHT_PWM_CTL_SHIFT (16)
static struct backlight_device * mdfld_backlight_device ;
int mdfld_set_brightness ( struct backlight_device * bd )
{
struct drm_device * dev =
( struct drm_device * ) bl_get_data ( mdfld_backlight_device ) ;
struct drm_psb_private * dev_priv = dev - > dev_private ;
int level = bd - > props . brightness ;
DRM_DEBUG_DRIVER ( " backlight level set to %d \n " , level ) ;
/* Perform value bounds checking */
if ( level < BRIGHTNESS_MIN_LEVEL )
level = BRIGHTNESS_MIN_LEVEL ;
if ( gma_power_begin ( dev , false ) ) {
u32 adjusted_level = 0 ;
/*
* Adjust the backlight level with the percent in
* dev_priv - > blc_adj2
*/
adjusted_level = level * dev_priv - > blc_adj2 ;
adjusted_level = adjusted_level / BLC_ADJUSTMENT_MAX ;
dev_priv - > brightness_adjusted = adjusted_level ;
if ( mdfld_get_panel_type ( dev , 0 ) = = TC35876X ) {
if ( dev_priv - > dpi_panel_on [ 0 ] | |
dev_priv - > dpi_panel_on [ 2 ] )
tc35876x_brightness_control ( dev ,
dev_priv - > brightness_adjusted ) ;
} else {
if ( dev_priv - > dpi_panel_on [ 0 ] )
mdfld_dsi_brightness_control ( dev , 0 ,
dev_priv - > brightness_adjusted ) ;
}
if ( dev_priv - > dpi_panel_on [ 2 ] )
mdfld_dsi_brightness_control ( dev , 2 ,
dev_priv - > brightness_adjusted ) ;
gma_power_end ( dev ) ;
}
/* cache the brightness for later use */
dev_priv - > brightness = level ;
return 0 ;
}
2012-03-08 16:11:14 +00:00
static int mdfld_get_brightness ( struct backlight_device * bd )
2012-03-08 16:02:20 +00:00
{
struct drm_device * dev =
( struct drm_device * ) bl_get_data ( mdfld_backlight_device ) ;
struct drm_psb_private * dev_priv = dev - > dev_private ;
DRM_DEBUG_DRIVER ( " brightness = 0x%x \n " , dev_priv - > brightness ) ;
/* return locally cached var instead of HW read (due to DPST etc.) */
return dev_priv - > brightness ;
}
static const struct backlight_ops mdfld_ops = {
. get_brightness = mdfld_get_brightness ,
. update_status = mdfld_set_brightness ,
} ;
static int device_backlight_init ( struct drm_device * dev )
{
struct drm_psb_private * dev_priv = ( struct drm_psb_private * )
dev - > dev_private ;
dev_priv - > blc_adj1 = BLC_ADJUSTMENT_MAX ;
dev_priv - > blc_adj2 = BLC_ADJUSTMENT_MAX ;
return 0 ;
}
2012-03-08 16:11:14 +00:00
static int mdfld_backlight_init ( struct drm_device * dev )
2012-03-08 16:02:20 +00:00
{
struct backlight_properties props ;
int ret = 0 ;
memset ( & props , 0 , sizeof ( struct backlight_properties ) ) ;
props . max_brightness = BRIGHTNESS_MAX_LEVEL ;
props . type = BACKLIGHT_PLATFORM ;
mdfld_backlight_device = backlight_device_register ( " mdfld-bl " ,
NULL , ( void * ) dev , & mdfld_ops , & props ) ;
if ( IS_ERR ( mdfld_backlight_device ) )
return PTR_ERR ( mdfld_backlight_device ) ;
ret = device_backlight_init ( dev ) ;
if ( ret )
return ret ;
mdfld_backlight_device - > props . brightness = BRIGHTNESS_MAX_LEVEL ;
mdfld_backlight_device - > props . max_brightness = BRIGHTNESS_MAX_LEVEL ;
backlight_update_status ( mdfld_backlight_device ) ;
return 0 ;
}
# endif
struct backlight_device * mdfld_get_backlight_device ( void )
{
# ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
return mdfld_backlight_device ;
# else
return NULL ;
# endif
}
/*
* mdfld_save_display_registers
*
* Description : We are going to suspend so save current display
* register state .
*
* Notes : FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
*/
2012-05-11 11:30:16 +01:00
static int mdfld_save_display_registers ( struct drm_device * dev , int pipenum )
2012-03-08 16:02:20 +00:00
{
struct drm_psb_private * dev_priv = dev - > dev_private ;
struct medfield_state * regs = & dev_priv - > regs . mdfld ;
2012-05-11 11:30:16 +01:00
struct psb_pipe * pipe = & dev_priv - > regs . pipe [ pipenum ] ;
2012-05-11 11:31:22 +01:00
const struct psb_offset * map = & dev_priv - > regmap [ pipenum ] ;
2012-03-08 16:02:20 +00:00
int i ;
2012-05-11 11:30:33 +01:00
u32 * mipi_val ;
2012-03-08 16:02:20 +00:00
/* register */
u32 mipi_reg = MIPI ;
2012-05-11 11:30:16 +01:00
switch ( pipenum ) {
2012-03-08 16:02:20 +00:00
case 0 :
2012-05-11 11:30:33 +01:00
mipi_val = & regs - > saveMIPI ;
2012-03-08 16:02:20 +00:00
break ;
case 1 :
2012-05-11 11:30:33 +01:00
mipi_val = & regs - > saveMIPI ;
2012-03-08 16:02:20 +00:00
break ;
case 2 :
/* register */
mipi_reg = MIPI_C ;
/* pointer to values */
mipi_val = & regs - > saveMIPI_C ;
break ;
default :
DRM_ERROR ( " %s, invalid pipe number. \n " , __func__ ) ;
return - EINVAL ;
}
/* Pipe & plane A info */
2012-05-11 11:31:22 +01:00
pipe - > dpll = PSB_RVDC32 ( map - > dpll ) ;
pipe - > fp0 = PSB_RVDC32 ( map - > fp0 ) ;
pipe - > conf = PSB_RVDC32 ( map - > conf ) ;
pipe - > htotal = PSB_RVDC32 ( map - > htotal ) ;
pipe - > hblank = PSB_RVDC32 ( map - > hblank ) ;
pipe - > hsync = PSB_RVDC32 ( map - > hsync ) ;
pipe - > vtotal = PSB_RVDC32 ( map - > vtotal ) ;
pipe - > vblank = PSB_RVDC32 ( map - > vblank ) ;
pipe - > vsync = PSB_RVDC32 ( map - > vsync ) ;
pipe - > src = PSB_RVDC32 ( map - > src ) ;
pipe - > stride = PSB_RVDC32 ( map - > stride ) ;
pipe - > linoff = PSB_RVDC32 ( map - > linoff ) ;
pipe - > tileoff = PSB_RVDC32 ( map - > tileoff ) ;
pipe - > size = PSB_RVDC32 ( map - > size ) ;
pipe - > pos = PSB_RVDC32 ( map - > pos ) ;
pipe - > surf = PSB_RVDC32 ( map - > surf ) ;
pipe - > cntr = PSB_RVDC32 ( map - > cntr ) ;
pipe - > status = PSB_RVDC32 ( map - > status ) ;
2012-03-08 16:02:20 +00:00
/*save palette (gamma) */
for ( i = 0 ; i < 256 ; i + + )
2012-05-11 11:31:22 +01:00
pipe - > palette [ i ] = PSB_RVDC32 ( map - > palette + ( i < < 2 ) ) ;
2012-03-08 16:02:20 +00:00
2012-05-11 11:30:16 +01:00
if ( pipenum = = 1 ) {
2012-03-08 16:02:20 +00:00
regs - > savePFIT_CONTROL = PSB_RVDC32 ( PFIT_CONTROL ) ;
regs - > savePFIT_PGM_RATIOS = PSB_RVDC32 ( PFIT_PGM_RATIOS ) ;
regs - > saveHDMIPHYMISCCTL = PSB_RVDC32 ( HDMIPHYMISCCTL ) ;
regs - > saveHDMIB_CONTROL = PSB_RVDC32 ( HDMIB_CONTROL ) ;
return 0 ;
}
* mipi_val = PSB_RVDC32 ( mipi_reg ) ;
return 0 ;
}
/*
* mdfld_restore_display_registers
*
* Description : We are going to resume so restore display register state .
*
* Notes : FIXME_JLIU7 need to add the support for DPI MIPI & HDMI audio
*/
2012-05-11 11:30:16 +01:00
static int mdfld_restore_display_registers ( struct drm_device * dev , int pipenum )
2012-03-08 16:02:20 +00:00
{
/* To get panel out of ULPS mode. */
u32 temp = 0 ;
u32 device_ready_reg = DEVICE_READY_REG ;
struct drm_psb_private * dev_priv = dev - > dev_private ;
struct mdfld_dsi_config * dsi_config = NULL ;
struct medfield_state * regs = & dev_priv - > regs . mdfld ;
2012-05-11 11:30:16 +01:00
struct psb_pipe * pipe = & dev_priv - > regs . pipe [ pipenum ] ;
2012-05-11 11:31:22 +01:00
const struct psb_offset * map = & dev_priv - > regmap [ pipenum ] ;
2012-05-11 11:30:33 +01:00
u32 i ;
u32 dpll ;
2012-03-08 16:02:20 +00:00
u32 timeout = 0 ;
2012-05-11 11:30:16 +01:00
/* register */
2012-03-08 16:02:20 +00:00
u32 mipi_reg = MIPI ;
/* values */
2012-05-11 11:30:16 +01:00
u32 dpll_val = pipe - > dpll ;
2012-03-08 16:02:20 +00:00
u32 mipi_val = regs - > saveMIPI ;
2012-05-11 11:30:16 +01:00
switch ( pipenum ) {
2012-03-08 16:02:20 +00:00
case 0 :
2012-05-11 11:30:16 +01:00
dpll_val & = ~ DPLL_VCO_ENABLE ;
2012-03-08 16:02:20 +00:00
dsi_config = dev_priv - > dsi_configs [ 0 ] ;
break ;
case 1 :
2012-05-11 11:30:16 +01:00
dpll_val & = ~ DPLL_VCO_ENABLE ;
2012-03-08 16:02:20 +00:00
break ;
case 2 :
mipi_reg = MIPI_C ;
mipi_val = regs - > saveMIPI_C ;
dsi_config = dev_priv - > dsi_configs [ 1 ] ;
break ;
default :
DRM_ERROR ( " %s, invalid pipe number. \n " , __func__ ) ;
return - EINVAL ;
}
/*make sure VGA plane is off. it initializes to on after reset!*/
PSB_WVDC32 ( 0x80000000 , VGACNTRL ) ;
2012-05-11 11:30:16 +01:00
if ( pipenum = = 1 ) {
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( dpll_val & ~ DPLL_VCO_ENABLE , map - > dpll ) ;
PSB_RVDC32 ( map - > dpll ) ;
2012-03-08 16:02:20 +00:00
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > fp0 , map - > fp0 ) ;
2012-03-08 16:02:20 +00:00
} else {
2012-05-11 11:31:22 +01:00
dpll = PSB_RVDC32 ( map - > dpll ) ;
2012-03-08 16:02:20 +00:00
if ( ! ( dpll & DPLL_VCO_ENABLE ) ) {
/* When ungating power of DPLL, needs to wait 0.5us
before enable the VCO */
if ( dpll & MDFLD_PWR_GATE_EN ) {
dpll & = ~ MDFLD_PWR_GATE_EN ;
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( dpll , map - > dpll ) ;
2012-03-08 16:02:20 +00:00
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay ( 500 ) ;
}
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > fp0 , map - > fp0 ) ;
PSB_WVDC32 ( dpll_val , map - > dpll ) ;
2012-03-08 16:02:20 +00:00
/* FIXME_MDFLD PO - change 500 to 1 after PO */
udelay ( 500 ) ;
dpll_val | = DPLL_VCO_ENABLE ;
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( dpll_val , map - > dpll ) ;
PSB_RVDC32 ( map - > dpll ) ;
2012-03-08 16:02:20 +00:00
/* wait for DSI PLL to lock */
while ( timeout < 20000 & &
2012-05-11 11:31:22 +01:00
! ( PSB_RVDC32 ( map - > conf ) & PIPECONF_DSIPLL_LOCK ) ) {
2012-03-08 16:02:20 +00:00
udelay ( 150 ) ;
timeout + + ;
}
if ( timeout = = 20000 ) {
DRM_ERROR ( " %s, can't lock DSIPLL. \n " ,
__func__ ) ;
return - EINVAL ;
}
}
}
/* Restore mode */
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > htotal , map - > htotal ) ;
PSB_WVDC32 ( pipe - > hblank , map - > hblank ) ;
PSB_WVDC32 ( pipe - > hsync , map - > hsync ) ;
PSB_WVDC32 ( pipe - > vtotal , map - > vtotal ) ;
PSB_WVDC32 ( pipe - > vblank , map - > vblank ) ;
PSB_WVDC32 ( pipe - > vsync , map - > vsync ) ;
PSB_WVDC32 ( pipe - > src , map - > src ) ;
PSB_WVDC32 ( pipe - > status , map - > status ) ;
2012-03-08 16:02:20 +00:00
/*set up the plane*/
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > stride , map - > stride ) ;
PSB_WVDC32 ( pipe - > linoff , map - > linoff ) ;
PSB_WVDC32 ( pipe - > tileoff , map - > tileoff ) ;
PSB_WVDC32 ( pipe - > size , map - > size ) ;
PSB_WVDC32 ( pipe - > pos , map - > pos ) ;
PSB_WVDC32 ( pipe - > surf , map - > surf ) ;
2012-03-08 16:02:20 +00:00
2012-05-11 11:30:16 +01:00
if ( pipenum = = 1 ) {
2012-03-08 16:02:20 +00:00
/* restore palette (gamma) */
/*DRM_UDELAY(50000); */
for ( i = 0 ; i < 256 ; i + + )
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > palette [ i ] , map - > palette + ( i < < 2 ) ) ;
2012-03-08 16:02:20 +00:00
PSB_WVDC32 ( regs - > savePFIT_CONTROL , PFIT_CONTROL ) ;
PSB_WVDC32 ( regs - > savePFIT_PGM_RATIOS , PFIT_PGM_RATIOS ) ;
/*TODO: resume HDMI port */
/*TODO: resume pipe*/
/*enable the plane*/
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > cntr & ~ DISPLAY_PLANE_ENABLE , map - > cntr ) ;
2012-03-08 16:02:20 +00:00
return 0 ;
}
/*set up pipe related registers*/
PSB_WVDC32 ( mipi_val , mipi_reg ) ;
/*setup MIPI adapter + MIPI IP registers*/
if ( dsi_config )
2012-05-11 11:30:16 +01:00
mdfld_dsi_controller_init ( dsi_config , pipenum ) ;
2012-03-08 16:02:20 +00:00
if ( in_atomic ( ) | | in_interrupt ( ) )
mdelay ( 20 ) ;
else
msleep ( 20 ) ;
/*enable the plane*/
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > cntr , map - > cntr ) ;
2012-03-08 16:02:20 +00:00
if ( in_atomic ( ) | | in_interrupt ( ) )
mdelay ( 20 ) ;
else
msleep ( 20 ) ;
/* LP Hold Release */
temp = REG_READ ( mipi_reg ) ;
temp | = LP_OUTPUT_HOLD_RELEASE ;
REG_WRITE ( mipi_reg , temp ) ;
mdelay ( 1 ) ;
/* Set DSI host to exit from Utra Low Power State */
temp = REG_READ ( device_ready_reg ) ;
temp & = ~ ULPS_MASK ;
temp | = 0x3 ;
temp | = EXIT_ULPS_DEV_READY ;
REG_WRITE ( device_ready_reg , temp ) ;
mdelay ( 1 ) ;
temp = REG_READ ( device_ready_reg ) ;
temp & = ~ ULPS_MASK ;
temp | = EXITING_ULPS ;
REG_WRITE ( device_ready_reg , temp ) ;
mdelay ( 1 ) ;
/*enable the pipe*/
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > conf , map - > conf ) ;
2012-03-08 16:02:20 +00:00
/* restore palette (gamma) */
/*DRM_UDELAY(50000); */
for ( i = 0 ; i < 256 ; i + + )
2012-05-11 11:31:22 +01:00
PSB_WVDC32 ( pipe - > palette [ i ] , map - > palette + ( i < < 2 ) ) ;
2012-03-08 16:02:20 +00:00
return 0 ;
}
static int mdfld_save_registers ( struct drm_device * dev )
{
/* mdfld_save_cursor_overlay_registers(dev); */
mdfld_save_display_registers ( dev , 0 ) ;
mdfld_save_display_registers ( dev , 2 ) ;
mdfld_disable_crtc ( dev , 0 ) ;
mdfld_disable_crtc ( dev , 2 ) ;
return 0 ;
}
static int mdfld_restore_registers ( struct drm_device * dev )
{
mdfld_restore_display_registers ( dev , 2 ) ;
mdfld_restore_display_registers ( dev , 0 ) ;
/* mdfld_restore_cursor_overlay_registers(dev); */
return 0 ;
}
static int mdfld_power_down ( struct drm_device * dev )
{
/* FIXME */
return 0 ;
}
static int mdfld_power_up ( struct drm_device * dev )
{
/* FIXME */
return 0 ;
}
2012-05-11 11:30:53 +01:00
/* Medfield */
static const struct psb_offset mdfld_regmap [ 3 ] = {
{
. fp0 = MRST_FPA0 ,
. fp1 = MRST_FPA1 ,
. cntr = DSPACNTR ,
. conf = PIPEACONF ,
. src = PIPEASRC ,
. dpll = MRST_DPLL_A ,
. htotal = HTOTAL_A ,
. hblank = HBLANK_A ,
. hsync = HSYNC_A ,
. vtotal = VTOTAL_A ,
. vblank = VBLANK_A ,
. vsync = VSYNC_A ,
. stride = DSPASTRIDE ,
. size = DSPASIZE ,
. pos = DSPAPOS ,
. surf = DSPASURF ,
2012-05-11 11:31:22 +01:00
. addr = MRST_DSPABASE ,
2012-05-11 11:30:53 +01:00
. status = PIPEASTAT ,
. linoff = DSPALINOFF ,
. tileoff = DSPATILEOFF ,
. palette = PALETTE_A ,
} ,
{
. fp0 = MDFLD_DPLL_DIV0 ,
. cntr = DSPBCNTR ,
. conf = PIPEBCONF ,
. src = PIPEBSRC ,
. dpll = MDFLD_DPLL_B ,
. htotal = HTOTAL_B ,
. hblank = HBLANK_B ,
. hsync = HSYNC_B ,
. vtotal = VTOTAL_B ,
. vblank = VBLANK_B ,
. vsync = VSYNC_B ,
. stride = DSPBSTRIDE ,
. size = DSPBSIZE ,
. pos = DSPBPOS ,
. surf = DSPBSURF ,
2012-05-11 11:31:22 +01:00
. addr = MRST_DSPBBASE ,
2012-05-11 11:30:53 +01:00
. status = PIPEBSTAT ,
. linoff = DSPBLINOFF ,
. tileoff = DSPBTILEOFF ,
. palette = PALETTE_B ,
} ,
{
2012-05-11 11:31:22 +01:00
. fp0 = MRST_FPA0 , /* This is what the old code did ?? */
2012-05-11 11:30:53 +01:00
. cntr = DSPCCNTR ,
. conf = PIPECCONF ,
. src = PIPECSRC ,
/* No DPLL_C */
. dpll = MRST_DPLL_A ,
. htotal = HTOTAL_C ,
. hblank = HBLANK_C ,
. hsync = HSYNC_C ,
. vtotal = VTOTAL_C ,
. vblank = VBLANK_C ,
. vsync = VSYNC_C ,
. stride = DSPCSTRIDE ,
. size = DSPBSIZE ,
. pos = DSPCPOS ,
. surf = DSPCSURF ,
2012-05-11 11:31:22 +01:00
. addr = MDFLD_DSPCBASE ,
2012-05-11 11:30:53 +01:00
. status = PIPECSTAT ,
. linoff = DSPCLINOFF ,
. tileoff = DSPCTILEOFF ,
. palette = PALETTE_C ,
} ,
} ;
static int mdfld_chip_setup ( struct drm_device * dev )
{
struct drm_psb_private * dev_priv = dev - > dev_private ;
2012-05-11 11:33:03 +01:00
if ( pci_enable_msi ( dev - > pdev ) )
dev_warn ( dev - > dev , " Enabling MSI failed! \n " ) ;
2012-05-11 11:30:53 +01:00
dev_priv - > regmap = mdfld_regmap ;
return mid_chip_setup ( dev ) ;
}
2012-03-08 16:02:20 +00:00
const struct psb_ops mdfld_chip_ops = {
. name = " mdfld " ,
. accel_2d = 0 ,
. pipes = 3 ,
. crtcs = 3 ,
2012-04-28 23:20:42 +02:00
. lvds_mask = ( 1 < < 1 ) ,
. hdmi_mask = ( 1 < < 1 ) ,
2012-03-08 16:02:20 +00:00
. sgx_offset = MRST_SGX_OFFSET ,
2012-05-11 11:30:53 +01:00
. chip_setup = mdfld_chip_setup ,
2012-03-08 16:02:20 +00:00
. crtc_helper = & mdfld_helper_funcs ,
. crtc_funcs = & psb_intel_crtc_funcs ,
. output_init = mdfld_output_init ,
# ifdef CONFIG_BACKLIGHT_CLASS_DEVICE
. backlight_init = mdfld_backlight_init ,
# endif
. save_regs = mdfld_save_registers ,
. restore_regs = mdfld_restore_registers ,
. power_down = mdfld_power_down ,
. power_up = mdfld_power_up ,
} ;