rk3036 tve: register fb notifier.
authorZheng Yang <zhengyang@rock-chips.com>
Thu, 31 Jul 2014 10:05:01 +0000 (18:05 +0800)
committerZheng Yang <zhengyang@rock-chips.com>
Thu, 31 Jul 2014 10:05:01 +0000 (18:05 +0800)
drivers/video/rockchip/tve/rk3036/rk3036_tve.c
drivers/video/rockchip/tve/rk3036/rk3036_tve.h

index 537674fa8e9c4f89cdc296abc53c8dddf641efc9..11095bfc1275cd981974bb5211f0534c600bc869 100644 (file)
@@ -1,8 +1,8 @@
 /*
- * rk3036_tve.c 
+ * rk3036_tve.c
  *
  * Driver for rockchip rk3036 tv encoder control
- * Copyright (C) 2014 
+ * Copyright (C) 2014
  *
  * This program is free software; you can redistribute  it and/or modify it
  * under  the terms of  the GNU General  Public License as published by the
@@ -21,7 +21,6 @@
 #include <linux/rockchip/iomap.h>
 #include "rk3036_tve.h"
 
-//#define DEBUG
 #ifdef DEBUG
 #define TVEDBG(format, ...) \
                printk(KERN_INFO "RK3036 TVE: " format "\n", ## __VA_ARGS__)
 #define TVEDBG(format, ...)
 #endif
 
-static const struct fb_videomode rk3036_cvbs_mode [] = {
-       /*name  refresh xres    yres    pixclock        h_bp    h_fp    v_bp    v_fp    h_pw    v_pw                    polariry                                PorI            flag*/
-       {"NTSC",60,     720,    480,    27000000,       57,     19,     19,     0,      62,     3,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   FB_VMODE_INTERLACED,    0},
-       {"PAL", 50,     720,    576,    27000000,       69,     12,     19,     2,      63,     3,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   FB_VMODE_INTERLACED,    0},
+static const struct fb_videomode rk3036_cvbs_mode[] = {
+       /*name          refresh xres    yres    pixclock        h_bp    h_fp    v_bp    v_fp    h_pw    v_pw                    polariry                                PorI            flag*/
+       {"NTSC",        60,     720,    480,    27000000,       57,     19,     19,     0,      62,     3,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   FB_VMODE_INTERLACED,    0},
+       {"PAL",         50,     720,    576,    27000000,       69,     12,     19,     2,      63,     3,      FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,   FB_VMODE_INTERLACED,    0},
 };
 
-static struct rk3036_tve *rk3036_tve = NULL;
+static struct rk3036_tve *rk3036_tve;
 
 #define tve_writel(offset, v)  writel_relaxed(v, rk3036_tve->regbase + offset)
 #define tve_readl(offset)      readl_relaxed(rk3036_tve->regbase + offset)
@@ -43,10 +42,10 @@ static struct rk3036_tve *rk3036_tve = NULL;
 static void dac_enable(bool enable)
 {
        u32 mask, val;
-       
-       TVEDBG("%s enable %d\n", __FUNCTION__, enable);
-       
-       if(enable) {
+
+       TVEDBG("%s enable %d\n", __func__, enable);
+
+       if (enable) {
                mask = m_VBG_EN | m_DAC_EN;
                val = mask;
        } else {
@@ -56,98 +55,101 @@ static void dac_enable(bool enable)
        grf_writel(RK3036_GRF_SOC_CON3, (mask << 16) | val);
 }
 
-static void tve_set_mode (int mode)
+static void tve_set_mode(int mode)
 {
-       TVEDBG("%s mode %d\n", __FUNCTION__, mode);
-       
+       TVEDBG("%s mode %d\n", __func__, mode);
+
        tve_writel(TV_RESET, v_RESET(1));
        udelay(100);
        tve_writel(TV_RESET, v_RESET(0));
-       
-       tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) | 
-                       v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) | 
-                       v_LUMA_FILTER_UPSAMPLE(0) | v_CSC_PATH(0) );
+
+       tve_writel(TV_CTRL, v_CVBS_MODE(mode) | v_CLK_UPSTREAM_EN(2) |
+                       v_TIMING_EN(2) | v_LUMA_FILTER_GAIN(0) |
+                       v_LUMA_FILTER_UPSAMPLE(1) | v_CSC_PATH(0));
        tve_writel(TV_LUMA_FILTER0, 0x02ff0000);
        tve_writel(TV_LUMA_FILTER1, 0xF40202fd);
        tve_writel(TV_LUMA_FILTER2, 0xF332d919);
-       
-       if(mode == TVOUT_CVBS_NTSC) {
-               tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(1) | 
-                       v_Y_AGC_PULSE_ON(1) | v_Y_VIDEO_ON(1) | 
-                       v_Y_SYNC_ON(1) | v_PIC_MODE(mode));
-               tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_NTSC) | v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3));
-               tve_writel(TV_SATURATION, 0x0052543C);
+
+       if (mode == TVOUT_CVBS_NTSC) {
+               tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(1) |
+                       v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) |
+                       v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode));
+               tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_NTSC) |
+                       v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3));
+               tve_writel(TV_SATURATION, 0x0042543C);
                tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00008300);
-               
+
                tve_writel(TV_FREQ_SC,  0x21F07BD7);
                tve_writel(TV_SYNC_TIMING, 0x00C07a81);
-               tve_writel(TV_ADJ_TIMING, 0x96B40000);
+               tve_writel(TV_ADJ_TIMING, 0x96B40000 | 0x70);
                tve_writel(TV_ACT_ST,   0x001500D6);
-               tve_writel(TV_ACT_TIMING, 0x169800FC);
+               tve_writel(TV_ACT_TIMING, 0x069800FC | (1 << 12) | (1 << 28));
 
        } else if (mode == TVOUT_CVBS_PAL) {
-               tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(0) | 
-                       v_Y_AGC_PULSE_ON(1) | v_Y_VIDEO_ON(1) | 
-                       v_Y_SYNC_ON(1) | v_CVBS_MODE(mode));
-               tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_PAL) | v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3));
-               tve_writel(TV_SATURATION, 0x002e553c);
-               tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00007579);
-               
+               tve_writel(TV_ROUTING, v_DAC_SENSE_EN(0) | v_Y_IRE_7_5(0) |
+                       v_Y_AGC_PULSE_ON(0) | v_Y_VIDEO_ON(1) |
+                       v_YPP_MODE(1) | v_Y_SYNC_ON(1) | v_PIC_MODE(mode));
+               tve_writel(TV_BW_CTRL, v_CHROMA_BW(BP_FILTER_PAL) |
+                       v_COLOR_DIFF_BW(COLOR_DIFF_FILTER_BW_1_3));
+               tve_writel(TV_SATURATION, 0x00325c40);
+               tve_writel(TV_BRIGHTNESS_CONTRAST, 0x00008b00);
+
                tve_writel(TV_FREQ_SC,  0x2A098ACB);
                tve_writel(TV_SYNC_TIMING, 0x00C28381);
-               tve_writel(TV_ADJ_TIMING, 0xB6C00880);
+               tve_writel(TV_ADJ_TIMING, (0xc << 28) | 0x06c00800 | 0x80);
                tve_writel(TV_ACT_ST,   0x001500F6);
-               tve_writel(TV_ACT_TIMING, 0x2694011D);
+               tve_writel(TV_ACT_TIMING, 0x0694011D | (1 << 12) | (2 << 28));
+               tve_writel(TV_ADJ_TIMING, (0xa << 28) | 0x06c00800 | 0x80);
        }
 }
 
 static int tve_switch_fb(const struct fb_videomode *modedb, int enable)
-{      
+{
        struct rk_screen *screen;
-       
-       if(modedb == NULL)
+
+       if (modedb == NULL)
                return -1;
-       screen =  kzalloc(sizeof(struct rk_screen), GFP_KERNEL);
-       if(screen == NULL)
+       screen =  kzalloc(sizeof(screen), GFP_KERNEL);
+       if (screen == NULL)
                return -1;
-       
-       memset(screen, 0, sizeof(struct rk_screen));    
+
+       memset(screen, 0, sizeof(struct rk_screen));
        /* screen type & face */
        screen->type = SCREEN_TVOUT;
        screen->face = OUT_P888;
-       
+
        screen->mode = *modedb;
-       
+
        /* Pin polarity */
-       if(FB_SYNC_HOR_HIGH_ACT & modedb->sync)
+       if (FB_SYNC_HOR_HIGH_ACT & modedb->sync)
                screen->pin_hsync = 1;
        else
                screen->pin_hsync = 0;
-       if(FB_SYNC_VERT_HIGH_ACT & modedb->sync)
+       if (FB_SYNC_VERT_HIGH_ACT & modedb->sync)
                screen->pin_vsync = 1;
        else
                screen->pin_vsync = 0;
-               
+
        screen->pin_den = 0;
        screen->pin_dclk = 0;
        screen->pixelrepeat = 1;
-       
+
        /* Swap rule */
        screen->swap_rb = 0;
        screen->swap_rg = 0;
        screen->swap_gb = 0;
        screen->swap_delta = 0;
        screen->swap_dumy = 0;
-       
+
        /* Operation function*/
        screen->init = NULL;
-       screen->standby = NULL; 
-       
+       screen->standby = NULL;
+
        rk_fb_switch_screen(screen, enable, 0);
 
        kfree(screen);
-       if(enable) {
-               if(screen->mode.yres == 480)
+       if (enable) {
+               if (screen->mode.yres == 480)
                        tve_set_mode(TVOUT_CVBS_NTSC);
                else
                        tve_set_mode(TVOUT_CVBS_PAL);
@@ -157,18 +159,16 @@ static int tve_switch_fb(const struct fb_videomode *modedb, int enable)
 
 static int cvbs_set_enable(struct rk_display_device *device, int enable)
 {
-       TVEDBG("%s enable %d\n", __FUNCTION__, enable);
-       if(rk3036_tve->enable != enable)
-       {
+       TVEDBG("%s enable %d\n", __func__, enable);
+       if (rk3036_tve->enable != enable) {
                rk3036_tve->enable = enable;
-               if(rk3036_tve->suspend)
+               if (rk3036_tve->suspend)
                        return 0;
-               
-               if(enable == 0) {
+
+               if (enable == 0) {
                        dac_enable(false);
                        tve_switch_fb(rk3036_tve->mode, 0);
-               }
-               else if(enable == 1) {
+               } else if (enable == 1) {
                        tve_switch_fb(rk3036_tve->mode, 1);
                        dac_enable(true);
                }
@@ -178,51 +178,97 @@ static int cvbs_set_enable(struct rk_display_device *device, int enable)
 
 static int cvbs_get_enable(struct rk_display_device *device)
 {
-       TVEDBG("%s enable %d\n", __FUNCTION__, rk3036_tve->enable);
+       TVEDBG("%s enable %d\n", __func__, rk3036_tve->enable);
        return rk3036_tve->enable;
 }
 
 static int cvbs_get_status(struct rk_display_device *device)
 {
-       TVEDBG("%s \n", __FUNCTION__);
        return 1;
 }
 
-static int cvbs_get_modelist(struct rk_display_device *device, struct list_head **modelist)
+static int
+cvbs_get_modelist(struct rk_display_device *device, struct list_head **modelist)
 {
-       TVEDBG("%s \n", __FUNCTION__);
        *modelist = &(rk3036_tve->modelist);
        return 0;
 }
 
-static int cvbs_set_mode(struct rk_display_device *device, struct fb_videomode *mode)
+static int
+cvbs_set_mode(struct rk_display_device *device, struct fb_videomode *mode)
 {
        int i;
-       TVEDBG("%s \n", __FUNCTION__);
-       for(i = 0; i < ARRAY_SIZE(rk3036_cvbs_mode); i++)
-       {
-               if(fb_mode_is_equal(&rk3036_cvbs_mode[i], mode))
-               {       
-                       if( rk3036_tve->mode != &rk3036_cvbs_mode[i] ) {
-                               rk3036_tve->mode = (struct fb_videomode *)&rk3036_cvbs_mode[i];
-                               if(rk3036_tve->enable && !rk3036_tve->suspend)
+
+       for (i = 0; i < ARRAY_SIZE(rk3036_cvbs_mode); i++) {
+               if (fb_mode_is_equal(&rk3036_cvbs_mode[i], mode)) {
+                       if (rk3036_tve->mode != &rk3036_cvbs_mode[i]) {
+                               rk3036_tve->mode =
+                               (struct fb_videomode *)&rk3036_cvbs_mode[i];
+                               if (rk3036_tve->enable && !rk3036_tve->suspend)
                                        dac_enable(false);
                                        tve_switch_fb(rk3036_tve->mode, 1);
+                                       msleep(500);
                                        dac_enable(true);
                        }
                        return 0;
                }
        }
-       
+       TVEDBG("%s\n", __func__);
        return -1;
 }
 
-static int cvbs_get_mode(struct rk_display_device *device, struct fb_videomode *mode)
+static int
+cvbs_get_mode(struct rk_display_device *device, struct fb_videomode *mode)
 {
        *mode = *(rk3036_tve->mode);
        return 0;
 }
 
+static int
+tve_fb_event_notify(struct notifier_block *self,
+                   unsigned long action, void *data)
+{
+       struct fb_event *event = data;
+       int blank_mode = *((int *)event->data);
+
+       if (action == FB_EARLY_EVENT_BLANK) {
+               switch (blank_mode) {
+               case FB_BLANK_UNBLANK:
+                       break;
+               default:
+                       TVEDBG("suspend hdmi\n");
+                       if (!rk3036_tve->suspend) {
+                               rk3036_tve->suspend = 1;
+                               if (rk3036_tve->enable) {
+                                       tve_switch_fb(rk3036_tve->mode, 0);
+                                       dac_enable(false);
+                               }
+                       }
+                       break;
+               }
+       } else if (action == FB_EVENT_BLANK) {
+               switch (blank_mode) {
+               case FB_BLANK_UNBLANK:
+                       TVEDBG("resume hdmi\n");
+                       if (rk3036_tve->suspend) {
+                               rk3036_tve->suspend = 0;
+                               if (rk3036_tve->enable) {
+                                       tve_switch_fb(rk3036_tve->mode, 1);
+                                       dac_enable(true);
+                               }
+                       }
+                       break;
+               default:
+                       break;
+               }
+       }
+       return NOTIFY_OK;
+}
+
+static struct notifier_block tve_fb_notifier = {
+       .notifier_call = tve_fb_event_notify,
+};
+
 static struct rk_display_ops cvbs_display_ops = {
        .setenable = cvbs_set_enable,
        .getenable = cvbs_get_enable,
@@ -232,7 +278,8 @@ static struct rk_display_ops cvbs_display_ops = {
        .getmode = cvbs_get_mode,
 };
 
-static int display_cvbs_probe(struct rk_display_device *device, void *devdata)
+static int
+display_cvbs_probe(struct rk_display_device *device, void *devdata)
 {
        device->owner = THIS_MODULE;
        strcpy(device->type, "TV");
@@ -251,10 +298,10 @@ static int rk3036_tve_probe(struct platform_device *pdev)
 {
        struct resource *res;
        int i;
-       
-       rk3036_tve = devm_kzalloc(&pdev->dev, sizeof(struct rk3036_tve), 
-                                       GFP_KERNEL);
-       if(!rk3036_tve) {
+
+       rk3036_tve = devm_kzalloc(&pdev->dev,
+                                 sizeof(struct rk3036_tve), GFP_KERNEL);
+       if (!rk3036_tve) {
                dev_err(&pdev->dev, "rk3036 tv encoder device kmalloc fail!");
                return -ENOMEM;
        }
@@ -263,31 +310,34 @@ static int rk3036_tve_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        rk3036_tve->reg_phy_base = res->start;
        rk3036_tve->len = resource_size(res);
-       rk3036_tve->regbase = devm_ioremap_resource(&pdev->dev, res);
+       rk3036_tve->regbase = ioremap(res->start, rk3036_tve->len);
        if (IS_ERR(rk3036_tve->regbase)) {
-               dev_err(&pdev->dev, "rk3036 tv encoder device map registers failed!");
+               dev_err(&pdev->dev,
+                       "rk3036 tv encoder device map registers failed!");
                return PTR_ERR(rk3036_tve->regbase);
-       }       
-       
+       }
+
        INIT_LIST_HEAD(&(rk3036_tve->modelist));
-       for(i = 0; i < ARRAY_SIZE(rk3036_cvbs_mode); i++)
+       for (i = 0; i < ARRAY_SIZE(rk3036_cvbs_mode); i++)
                fb_add_videomode(&rk3036_cvbs_mode[i], &(rk3036_tve->modelist));
-       rk3036_tve->mode = (struct fb_videomode*)&rk3036_cvbs_mode[1];
-       rk3036_tve->ddev = rk_display_device_register(&display_cvbs, &pdev->dev, NULL);
+       rk3036_tve->mode = (struct fb_videomode *)&rk3036_cvbs_mode[1];
+       rk3036_tve->ddev =
+               rk_display_device_register(&display_cvbs, &pdev->dev, NULL);
        rk_display_device_enable(rk3036_tve->ddev);
-       
+
+       fb_register_client(&tve_fb_notifier);
        dev_info(&pdev->dev, "rk3036 tv encoder probe ok\n");
        return 0;
 }
 
 static void rk3036_tve_shutdown(struct platform_device *pdev)
 {
-       
 }
 
 #if defined(CONFIG_OF)
 static const struct of_device_id rk3036_tve_dt_ids[] = {
        {.compatible = "rockchip,rk3036-tve",},
+       {.compatible = "rockchip,rk312x-tve",},
        {}
 };
 #endif
@@ -310,7 +360,7 @@ static int __init rk3036_tve_init(void)
 
 static void __exit rk3036_tve_exit(void)
 {
-    platform_driver_unregister(&rk3036_tve_driver);
+       platform_driver_unregister(&rk3036_tve_driver);
 }
 
 module_init(rk3036_tve_init);
index d36573e0f5b078b0e809574738457d21dc388f1d..25ebd2190520db603fbda530f3bec6d20b21c6ae 100644 (file)
@@ -8,14 +8,14 @@
        #define m_LUMA_FILTER_GAIN              (3 << 9)
        #define m_LUMA_FILTER_BW                (1 << 8)
        #define m_CSC_PATH                      (3 << 1)
-       
-       #define v_CVBS_MODE(x)                  ( (x & 1) << 24)
-       #define v_CLK_UPSTREAM_EN(x)            ( (x & 3) << 18)
-       #define v_TIMING_EN(x)                  ( (x & 3) << 16)
-       #define v_LUMA_FILTER_GAIN(x)           ( (x & 3) << 9)
-       #define v_LUMA_FILTER_UPSAMPLE(x)       ( (x & 1) << 8)
-       #define v_CSC_PATH(x)                   ( (x & 3) << 1)
-       
+
+       #define v_CVBS_MODE(x)                  ((x & 1) << 24)
+       #define v_CLK_UPSTREAM_EN(x)            ((x & 3) << 18)
+       #define v_TIMING_EN(x)                  ((x & 3) << 16)
+       #define v_LUMA_FILTER_GAIN(x)           ((x & 3) << 9)
+       #define v_LUMA_FILTER_UPSAMPLE(x)       ((x & 1) << 8)
+       #define v_CSC_PATH(x)                   ((x & 3) << 1)
+
 #define TV_SYNC_TIMING         (0x04)
 #define TV_ACT_TIMING          (0x08)
 #define TV_ADJ_TIMING          (0x0c)
        #define m_Y_AGC_PULSE_ON        (1 << 15)
        #define m_Y_VIDEO_ON            (1 << 11)
        #define m_Y_SYNC_ON             (1 << 7)
+       #define m_YPP_MODE              (1 << 3)
        #define m_MONO_EN               (1 << 2)
        #define m_PIC_MODE              (1 << 1)
-       
-       #define v_DAC_SENSE_EN(x)       ( (x & 1) << 27)
-       #define v_Y_IRE_7_5(x)          ( (x & 1) << 19)
-       #define v_Y_AGC_PULSE_ON(x)     ( (x & 1) << 15)
-       #define v_Y_VIDEO_ON(x)         ( (x & 1) << 11)
-       #define v_Y_SYNC_ON(x)          ( (x & 1) << 7)
-       #define v_MONO_EN(x)            ( (x & 1) << 2)
-       #define v_PIC_MODE(x)           ( (x & 1) << 1)
-       
+
+       #define v_DAC_SENSE_EN(x)       ((x & 1) << 27)
+       #define v_Y_IRE_7_5(x)          ((x & 1) << 19)
+       #define v_Y_AGC_PULSE_ON(x)     ((x & 1) << 15)
+       #define v_Y_VIDEO_ON(x)         ((x & 1) << 11)
+       #define v_Y_SYNC_ON(x)          ((x & 1) << 7)
+       #define v_YPP_MODE(x)           ((x & 1) << 3)
+       #define v_MONO_EN(x)            ((x & 1) << 2)
+       #define v_PIC_MODE(x)           ((x & 1) << 1)
+
 #define TV_SYNC_ADJUST         (0x50)
 #define TV_STATUS              (0x54)
 #define TV_RESET               (0x68)
-       #define m_RESET                 (1 << 1);
-       #define v_RESET(x)              ( (x & 1) << 1)
+       #define m_RESET                 (1 << 1)
+       #define v_RESET(x)              ((x & 1) << 1)
 #define TV_SATURATION          (0x78)
 #define TV_BW_CTRL             (0x8C)
        #define m_CHROMA_BW     (3 << 4)
        #define m_COLOR_DIFF_BW (0xf)
-       
+
        enum {
                BP_FILTER_PASS = 0,
                BP_FILTER_NTSC,
                COLOR_DIFF_FILTER_BW_1_3,
                COLOR_DIFF_FILTER_BW_2_0
        };
-       
+
        #define v_CHROMA_BW(x)          ((3 & x) << 4)
        #define v_COLOR_DIFF_BW(x)      (0xF & x)
-       
+
 #define TV_BRIGHTNESS_CONTRAST (0x90)
 
 #define m_EXTREF_EN            (1 << 0)
@@ -74,6 +76,7 @@
 #define m_SENSE_EN             (1 << 3)
 #define m_BIAS_EN              (7 << 4)
 #define m_DAC_GAIN             (0x3f << 7)
+#define v_DAC_GAIN(x)          ((x & 0x3f) << 7)
 
 enum {
        TVOUT_CVBS_NTSC = 0,
@@ -82,14 +85,17 @@ enum {
 
 #define TVOUT_DEAULT TVOUT_CVBS_PAL
 
-#define grf_writel(offset, v)  do{ writel_relaxed(v, RK_GRF_VIRT + offset);dsb();} while (0)
+#define grf_writel(offset, v)  do { \
+       writel_relaxed(v, RK_GRF_VIRT + offset); \
+       dsb(); \
+       } while (0)
 
 struct rk3036_tve {
-       struct device                   *dev;   
+       struct device                   *dev;
        void __iomem                    *regbase;
-       u32                             reg_phy_base;   /* physical basic address of register*/
-       u32                             len;            /* physical map length of register*/
-       
+       u32                             reg_phy_base;
+       u32                             len;
+
        struct rk_display_device        *ddev;
        unsigned int                    enable;
        unsigned int                    suspend;