/* Interrupt debounce timer */
static void tvout_msm_hpd_state_timer(unsigned long data)
{
#ifdef CONFIG_SUSPEND
	mutex_lock(&tvout_msm_state_mutex);
	if (tvout_msm_state->pm_suspended) {
		mutex_unlock(&tvout_msm_state_mutex);
		DEV_WARN("%s: ignored, pm_suspended\n", __func__);
		return;
	}
	mutex_unlock(&tvout_msm_state_mutex);
#endif

	if (tvenc_pdata->poll)
		if (!tvout_msm_state || !tvout_msm_state->disp_powered_up) {
			DEV_DBG("%s: ignored, display powered off\n", __func__);
			return;
		}

	/* TV_INTR_STATUS[0x204]
		When a TV_ENC interrupt occurs, then reading this register will
		indicate what caused the interrupt since that each bit indicates
		the source of the interrupt that had happened. If multiple
		interrupt sources had happened, then multiple bits of this
		register will be set
		Bit 0 : Load present on Video1
		Bit 1 : Load present on Video2
		Bit 2 : Load removed on Video1
		Bit 3 : Load removed on Video2
	*/

	/* Locking interrupt status is not required because
	last status read after debouncing is used */
	if ((tvout_msm_state->hpd_int_status & 0x05) == 0x05) {
		/* SW-workaround :If the status read after debouncing is
		0x05(indicating both load present & load removed- which can't
		happen in reality), force an update. If status remains 0x05
		after retry, it's a cable unplug event */
		if (++tvout_msm_state->five_retry < 2) {
			uint32 reg;
			DEV_DBG("tvout: Timer: 0x05\n");
			TV_OUT(TV_INTR_CLEAR, 0xf);
			reg = TV_IN(TV_DAC_INTF);
			TV_OUT(TV_DAC_INTF, reg & ~TVENC_LOAD_DETECT_EN);
			TV_OUT(TV_INTR_CLEAR, 0xf);
			reg = TV_IN(TV_DAC_INTF);
			TV_OUT(TV_DAC_INTF, reg | TVENC_LOAD_DETECT_EN);
			return;
		}
	}
	tvout_msm_state->five_retry = 0;
	tvout_check_status();
}
static void tvout_msm_hpd_work(struct work_struct *work)
{
	uint32 reg;

#ifdef CONFIG_SUSPEND
	mutex_lock(&tvout_msm_state_mutex);
	if (tvout_msm_state->pm_suspended) {
		mutex_unlock(&tvout_msm_state_mutex);
		DEV_WARN("%s: ignored, pm_suspended\n", __func__);
		return;
	}
	mutex_unlock(&tvout_msm_state_mutex);
#endif

	/* Enable power lines & clocks */
	tvenc_pdata->pm_vid_en(1);
	tvenc_set_clock(CLOCK_ON);

	/* Enable encoder to get a stable interrupt */
	reg = TV_IN(TV_ENC_CTL);
	TV_OUT(TV_ENC_CTL, reg | TVENC_CTL_ENC_EN);

	/* SW- workaround to update status register */
	reg = TV_IN(TV_DAC_INTF);
	TV_OUT(TV_DAC_INTF, reg & ~TVENC_LOAD_DETECT_EN);
	TV_OUT(TV_INTR_CLEAR, 0xf);
	reg = TV_IN(TV_DAC_INTF);
	TV_OUT(TV_DAC_INTF, reg | TVENC_LOAD_DETECT_EN);

	tvout_msm_state->hpd_int_status = TV_IN(TV_INTR_STATUS);

	/* Disable TV encoder */
	reg = TV_IN(TV_ENC_CTL);
	TV_OUT(TV_ENC_CTL, reg & ~TVENC_CTL_ENC_EN);

	/*Disable power lines & clocks */
	tvenc_set_clock(CLOCK_OFF);
	tvenc_pdata->pm_vid_en(0);

	DEV_DBG("%s: ISR: 0x%02x\n", __func__,
		tvout_msm_state->hpd_int_status & 0x05);

	mod_timer(&tvout_msm_state->hpd_work_timer, jiffies
		+ msecs_to_jiffies(TVOUT_HPD_DUTY_CYCLE));

	tvout_check_status();
}
static void tvout_msm_turn_on(boolean power_on)
{
	uint32 reg_val = 0;
	reg_val = TV_IN(TV_ENC_CTL);
	if (power_on) {
		DEV_DBG("%s: TV Encoder turned on\n", __func__);
		reg_val |= TVENC_CTL_ENC_EN;
	} else {
		DEV_DBG("%s: TV Encoder turned off\n", __func__);
		reg_val = 0;
	}
	/* Enable TV Encoder*/
	TV_OUT(TV_ENC_CTL, reg_val);
}
Exemplo n.º 4
0
/* ISR for TV out cable detect */
static irqreturn_t tvout_msm_isr(int irq, void *dev_id)
{
	tvout_msm_state->hpd_int_status = TV_IN(TV_INTR_STATUS);
	TV_OUT(TV_INTR_CLEAR, tvout_msm_state->hpd_int_status);
	TV_OUT_DEBUG("%s: ISR: 0x%02x\n", __func__,
		tvout_msm_state->hpd_int_status & 0x05);

	if (!tvout_msm_state || !tvout_msm_state->disp_powered_up) {
		TV_OUT_DEBUG("%s: ISR ignored, display not yet powered on\n",
			__func__);
		return IRQ_HANDLED;
	}
	if (tvout_msm_state->hpd_int_status & BIT(0) ||
		tvout_msm_state->hpd_int_status & BIT(2)) {
		/* Use .75sec to debounce the interrupt */
		mod_timer(&tvout_msm_state->hpd_state_timer, jiffies
			+ msecs_to_jiffies(750));
	}

	return IRQ_HANDLED;
}
static int __devinit tvout_probe(struct platform_device *pdev)
{
	int rc = 0;
	uint32 reg;
	struct platform_device *fb_dev;

#ifdef CONFIG_FB_MSM_TVOUT_NTSC_M
	external_common_state->video_resolution = NTSC_M;
#elif defined CONFIG_FB_MSM_TVOUT_NTSC_J
	external_common_state->video_resolution = NTSC_J;
#elif defined CONFIG_FB_MSM_TVOUT_PAL_M
	external_common_state->video_resolution = PAL_M;
#elif defined CONFIG_FB_MSM_TVOUT_PAL_N
	external_common_state->video_resolution = PAL_N;
#elif defined CONFIG_FB_MSM_TVOUT_PAL_BDGHIN
	external_common_state->video_resolution = PAL_BDGHIN;
#endif
	external_common_state->dev = &pdev->dev;
	if (pdev->id == 0) {
		struct resource *res;

		#define GET_RES(name, mode) do {			\
			res = platform_get_resource_byname(pdev, mode, name); \
			if (!res) {					\
				DEV_DBG("'" name "' resource not found\n"); \
				rc = -ENODEV;				\
				goto error;				\
			}						\
		} while (0)

		#define GET_IRQ(var, name) do {				\
			GET_RES(name, IORESOURCE_IRQ);			\
			var = res->start;				\
		} while (0)

		GET_IRQ(tvout_msm_state->irq, "tvout_device_irq");
		#undef GET_IRQ
		#undef GET_RES
		return 0;
	}

	DEV_DBG("%s: tvout_msm_state->irq : %d",
			__func__, tvout_msm_state->irq);

	rc = request_irq(tvout_msm_state->irq, &tvout_msm_isr,
		IRQF_TRIGGER_HIGH, "tvout_msm_isr", NULL);

	if (rc) {
		DEV_DBG("Init FAILED: IRQ request, rc=%d\n", rc);
		goto error;
	}
	disable_irq(tvout_msm_state->irq);

	init_timer(&tvout_msm_state->hpd_state_timer);
	tvout_msm_state->hpd_state_timer.function =
		tvout_msm_hpd_state_timer;
	tvout_msm_state->hpd_state_timer.data = (uint32)NULL;
	tvout_msm_state->hpd_state_timer.expires = jiffies
						+ msecs_to_jiffies(1000);

	if (tvenc_pdata->poll) {
		init_timer(&tvout_msm_state->hpd_work_timer);
		tvout_msm_state->hpd_work_timer.function =
			tvout_msm_hpd_work_timer;
		tvout_msm_state->hpd_work_timer.data = (uint32)NULL;
		tvout_msm_state->hpd_work_timer.expires = jiffies
						+ msecs_to_jiffies(1000);
	}
	fb_dev = msm_fb_add_device(pdev);
	if (fb_dev) {
		rc = external_common_state_create(fb_dev);
		if (rc) {
			DEV_ERR("Init FAILED: tvout_msm_state_create, rc=%d\n",
				rc);
			goto error;
		}
		if (tvenc_pdata->poll) {
			/* Start polling timer to detect load */
			mod_timer(&tvout_msm_state->hpd_work_timer, jiffies
				+ msecs_to_jiffies(TVOUT_HPD_DUTY_CYCLE));
		} else {
			/* Enable interrupt to detect load */
			tvenc_set_encoder_clock(CLOCK_ON);
			reg = TV_IN(TV_DAC_INTF);
			reg |= TVENC_LOAD_DETECT_EN;
			TV_OUT(TV_DAC_INTF, reg);
			TV_OUT(TV_INTR_ENABLE, 0x5);
			enable_irq(tvout_msm_state->irq);
		}
	} else
		DEV_ERR("Init FAILED: failed to add fb device\n");
error:
	return 0;
}
static int tvout_on(struct platform_device *pdev)
{
	uint32 reg = 0;
	struct fb_var_screeninfo *var;
	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);

	if (!mfd)
		return -ENODEV;

	if (mfd->key != MFD_KEY)
		return -EINVAL;

#ifdef CONFIG_SUSPEND
	mutex_lock(&tvout_msm_state_mutex);
	if (tvout_msm_state->pm_suspended) {
		mutex_unlock(&tvout_msm_state_mutex);
		DEV_WARN("%s: ignored, pm_suspended\n", __func__);
		return -ENODEV;
	}
	mutex_unlock(&tvout_msm_state_mutex);
#endif

	var = &mfd->fbi->var;
	if (var->reserved[3] >= NTSC_M && var->reserved[3] <= PAL_N)
		external_common_state->video_resolution = var->reserved[3];

	tvout_msm_state->pdev = pdev;
	if (del_timer(&tvout_msm_state->hpd_work_timer))
		DEV_DBG("%s: work timer stopped\n", __func__);

	TV_OUT(TV_ENC_CTL, 0);	/* disable TV encoder */

	switch (external_common_state->video_resolution) {
	case NTSC_M:
	case NTSC_J:
		TV_OUT(TV_CGMS, 0x0);
		/*  NTSC Timing */
		TV_OUT(TV_SYNC_1, 0x0020009e);
		TV_OUT(TV_SYNC_2, 0x011306B4);
		TV_OUT(TV_SYNC_3, 0x0006000C);
		TV_OUT(TV_SYNC_4, 0x0028020D);
		TV_OUT(TV_SYNC_5, 0x005E02FB);
		TV_OUT(TV_SYNC_6, 0x0006000C);
		TV_OUT(TV_SYNC_7, 0x00000012);
		TV_OUT(TV_BURST_V1, 0x0013020D);
		TV_OUT(TV_BURST_V2, 0x0014020C);
		TV_OUT(TV_BURST_V3, 0x0013020D);
		TV_OUT(TV_BURST_V4, 0x0014020C);
		TV_OUT(TV_BURST_H, 0x00AE00F2);
		TV_OUT(TV_SOL_REQ_ODD, 0x00280208);
		TV_OUT(TV_SOL_REQ_EVEN, 0x00290209);

		reg |= TVENC_CTL_TV_MODE_NTSC_M_PAL60;

		if (external_common_state->video_resolution == NTSC_M) {
			/* Cr gain 11, Cb gain C6, y_gain 97 */
			TV_OUT(TV_GAIN, 0x0081B697);
		} else {
			/* Cr gain 11, Cb gain C6, y_gain 97 */
			TV_OUT(TV_GAIN, 0x008bc4a3);
			reg |= TVENC_CTL_NTSCJ_MODE;
		}

		var->yres = 480;
		break;
	case PAL_BDGHIN:
	case PAL_N:
		/*  PAL Timing */
		TV_OUT(TV_SYNC_1, 0x00180097);
		TV_OUT(TV_SYNC_3, 0x0005000a);
		TV_OUT(TV_SYNC_4, 0x00320271);
		TV_OUT(TV_SYNC_5, 0x005602f9);
		TV_OUT(TV_SYNC_6, 0x0005000a);
		TV_OUT(TV_SYNC_7, 0x0000000f);
		TV_OUT(TV_BURST_V1, 0x0012026e);
		TV_OUT(TV_BURST_V2, 0x0011026d);
		TV_OUT(TV_BURST_V3, 0x00100270);
		TV_OUT(TV_BURST_V4, 0x0013026f);
		TV_OUT(TV_SOL_REQ_ODD, 0x0030026e);
		TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f);

		if (external_common_state->video_resolution == PAL_BDGHIN) {
			/* Cr gain 11, Cb gain C6, y_gain 97 */
			TV_OUT(TV_GAIN, 0x0088c1a0);
			TV_OUT(TV_CGMS, 0x00012345);
			TV_OUT(TV_SYNC_2, 0x011f06c0);
			TV_OUT(TV_BURST_H, 0x00af00ea);
			reg |= TVENC_CTL_TV_MODE_PAL_BDGHIN;
		} else {
			/* Cr gain 11, Cb gain C6, y_gain 97 */
			TV_OUT(TV_GAIN, 0x0081b697);
			TV_OUT(TV_CGMS, 0x000af317);
			TV_OUT(TV_SYNC_2, 0x12006c0);
			TV_OUT(TV_BURST_H, 0x00af00fa);
			reg |= TVENC_CTL_TV_MODE_PAL_N;
		}
		var->yres = 576;
		break;
	case PAL_M:
		/* Cr gain 11, Cb gain C6, y_gain 97 */
		TV_OUT(TV_GAIN, 0x0081b697);
		TV_OUT(TV_CGMS, 0x000af317);
		TV_OUT(TV_TEST_MUX, 0x000001c3);
		TV_OUT(TV_TEST_MODE, 0x00000002);
		/*  PAL Timing */
		TV_OUT(TV_SYNC_1, 0x0020009e);
		TV_OUT(TV_SYNC_2, 0x011306b4);
		TV_OUT(TV_SYNC_3, 0x0006000c);
		TV_OUT(TV_SYNC_4, 0x0028020D);
		TV_OUT(TV_SYNC_5, 0x005e02fb);
		TV_OUT(TV_SYNC_6, 0x0006000c);
		TV_OUT(TV_SYNC_7, 0x00000012);
		TV_OUT(TV_BURST_V1, 0x0012020b);
		TV_OUT(TV_BURST_V2, 0x0016020c);
		TV_OUT(TV_BURST_V3, 0x00150209);
		TV_OUT(TV_BURST_V4, 0x0013020c);
		TV_OUT(TV_BURST_H, 0x00bf010b);
		TV_OUT(TV_SOL_REQ_ODD, 0x00280208);
		TV_OUT(TV_SOL_REQ_EVEN, 0x00290209);

		reg |= TVENC_CTL_TV_MODE_PAL_M;
		var->yres = 480;
		break;
	default:
		return -ENODEV;
	}

	reg |= TVENC_CTL_Y_FILTER_EN | TVENC_CTL_CR_FILTER_EN |
		TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN;

	/* DC offset to 0. */
	TV_OUT(TV_LEVEL, 0x00000000);
	TV_OUT(TV_OFFSET, 0x008080f0);

#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO
	reg |= TVENC_CTL_S_VIDEO_EN;
#endif
#if defined(CONFIG_FB_MSM_MDP31)
	TV_OUT(TV_DAC_INTF, 0x29);
#endif
	TV_OUT(TV_ENC_CTL, reg);

	if (!tvout_msm_state->hpd_initialized) {
		tvout_msm_state->hpd_initialized = TRUE;
		/* Load detect enable */
		reg = TV_IN(TV_DAC_INTF);
		reg |= TVENC_LOAD_DETECT_EN;
		TV_OUT(TV_DAC_INTF, reg);
	}

	tvout_msm_state->disp_powered_up = TRUE;
	tvout_msm_turn_on(TRUE);

	if (tvenc_pdata->poll) {
		/* Enable Load present & removal interrupts for Video1 */
		TV_OUT(TV_INTR_ENABLE, 0x5);

		/* Enable interrupts when display is on */
		enable_irq(tvout_msm_state->irq);
	}
	return 0;
}
Exemplo n.º 7
0
static int tvout_on(struct platform_device *pdev)
{
	uint32 reg = 0;
	int ret = 0, rc;
	struct fb_var_screeninfo *var;
	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);;

	if (!mfd)
		return -ENODEV;

	if (mfd->key != MFD_KEY)
		return -EINVAL;

	var = &mfd->fbi->var;

#ifdef CONFIG_HUAWEI_KERNEL
	if(TVOUT_PAL == var->reserved[4])
	{
		tvout_msm_state->video_mode = PAL_M;
	}
	else
	{
		tvout_msm_state->video_mode = NTSC_M;
	}
#endif
	if (!tvout_msm_state->uevent_kobj) {
		rc = tvout_msm_state_create(pdev);
		if (rc) {
			pr_err("Init FAILED: tvout_msm_state_create, rc=%d\n",
				rc);
			goto error;
		}
		kobject_uevent(tvout_msm_state->uevent_kobj, KOBJ_ADD);
		pr_info("%s: kobject_uevent(KOBJ_ADD)\n", __func__);
	}

	TV_OUT(TV_ENC_CTL, 0);	/* disable TV encoder */

	switch (tvout_msm_state->video_mode) {
	case NTSC_M:
	case NTSC_J:
		TV_OUT(TV_CGMS, 0x0);
		/*  NTSC Timing */
		TV_OUT(TV_SYNC_1, 0x0020009e);
		TV_OUT(TV_SYNC_2, 0x011306B4);
		TV_OUT(TV_SYNC_3, 0x0006000C);
		TV_OUT(TV_SYNC_4, 0x0028020D);
		TV_OUT(TV_SYNC_5, 0x005E02FB);
		TV_OUT(TV_SYNC_6, 0x0006000C);
		TV_OUT(TV_SYNC_7, 0x00000012);
		TV_OUT(TV_BURST_V1, 0x0013020D);
		TV_OUT(TV_BURST_V2, 0x0014020C);
		TV_OUT(TV_BURST_V3, 0x0013020D);
		TV_OUT(TV_BURST_V4, 0x0014020C);
		TV_OUT(TV_BURST_H, 0x00AE00F2);
		TV_OUT(TV_SOL_REQ_ODD, 0x00280208);
		TV_OUT(TV_SOL_REQ_EVEN, 0x00290209);

		reg |= TVENC_CTL_TV_MODE_NTSC_M_PAL60;

		if (tvout_msm_state->video_mode == NTSC_M) {
			/* Cr gain 11, Cb gain C6, y_gain 97 */
			TV_OUT(TV_GAIN, 0x0081B697);
		} else {
			/* Cr gain 11, Cb gain C6, y_gain 97 */
			TV_OUT(TV_GAIN, 0x008bc4a3);
			reg |= TVENC_CTL_NTSCJ_MODE;
		}

		var->yres = 480;
		break;
	case PAL_BDGHIN:
	case PAL_N:
		/*  PAL Timing */
		TV_OUT(TV_SYNC_1, 0x00180097);
		TV_OUT(TV_SYNC_3, 0x0005000a);
		TV_OUT(TV_SYNC_4, 0x00320271);
		TV_OUT(TV_SYNC_5, 0x005602f9);
		TV_OUT(TV_SYNC_6, 0x0005000a);
		TV_OUT(TV_SYNC_7, 0x0000000f);
		TV_OUT(TV_BURST_V1, 0x0012026e);
		TV_OUT(TV_BURST_V2, 0x0011026d);
		TV_OUT(TV_BURST_V3, 0x00100270);
		TV_OUT(TV_BURST_V4, 0x0013026f);
		TV_OUT(TV_SOL_REQ_ODD, 0x0030026e);
		TV_OUT(TV_SOL_REQ_EVEN, 0x0031026f);

		if (tvout_msm_state->video_mode == PAL_BDGHIN) {
			/* Cr gain 11, Cb gain C6, y_gain 97 */
			TV_OUT(TV_GAIN, 0x0088c1a0);
			TV_OUT(TV_CGMS, 0x00012345);
			TV_OUT(TV_SYNC_2, 0x011f06c0);
			TV_OUT(TV_BURST_H, 0x00af00ea);
			reg |= TVENC_CTL_TV_MODE_PAL_BDGHIN;
		} else {
			/* Cr gain 11, Cb gain C6, y_gain 97 */
			TV_OUT(TV_GAIN, 0x0081b697);
			TV_OUT(TV_CGMS, 0x000af317);
			TV_OUT(TV_SYNC_2, 0x12006c0);
			TV_OUT(TV_BURST_H, 0x00af00fa);
			reg |= TVENC_CTL_TV_MODE_PAL_N;
		}
		var->yres = 576;
		break;
	case PAL_M:
		/* Cr gain 11, Cb gain C6, y_gain 97 */
		TV_OUT(TV_GAIN, 0x0081b697);
		TV_OUT(TV_CGMS, 0x000af317);
		TV_OUT(TV_TEST_MUX, 0x000001c3);
		TV_OUT(TV_TEST_MODE, 0x00000002);
		/*  PAL Timing */
		TV_OUT(TV_SYNC_1, 0x0020009e);
		TV_OUT(TV_SYNC_2, 0x011306b4);
		TV_OUT(TV_SYNC_3, 0x0006000c);
		TV_OUT(TV_SYNC_4, 0x0028020D);
		TV_OUT(TV_SYNC_5, 0x005e02fb);
		TV_OUT(TV_SYNC_6, 0x0006000c);
		TV_OUT(TV_SYNC_7, 0x00000012);
		TV_OUT(TV_BURST_V1, 0x0012020b);
		TV_OUT(TV_BURST_V2, 0x0016020c);
		TV_OUT(TV_BURST_V3, 0x00150209);
		TV_OUT(TV_BURST_V4, 0x0013020c);
		TV_OUT(TV_BURST_H, 0x00bf010b);
		TV_OUT(TV_SOL_REQ_ODD, 0x00280208);
		TV_OUT(TV_SOL_REQ_EVEN, 0x00290209);

		reg |= TVENC_CTL_TV_MODE_PAL_M;
		var->yres = 480;
		break;
	default:
		return -ENODEV;
	}

#ifdef CONFIG_FB_MSM_TVOUT_SVIDEO
	reg |= TVENC_CTL_S_VIDEO_EN;
#endif

	reg |= TVENC_CTL_Y_FILTER_EN |
	    TVENC_CTL_CR_FILTER_EN |
	    TVENC_CTL_CB_FILTER_EN | TVENC_CTL_SINX_FILTER_EN;

	/* DC offset to 0. */
	TV_OUT(TV_LEVEL, 0x00000000);
	TV_OUT(TV_OFFSET, 0x008080f0);

#if defined(CONFIG_FB_MSM_MDP31)
	TV_OUT(TV_DAC_INTF, 0x29);
#endif
	TV_OUT(TV_ENC_CTL, reg);

	/* Enable TV Out */
	reg |= TVENC_CTL_ENC_EN;
	TV_OUT(TV_ENC_CTL, reg);
	reg = TV_IN(TV_DAC_INTF);
	reg |= TVENC_LOAD_DETECT_EN;
	TV_OUT(TV_DAC_INTF, reg);
	/* Enable Load present & removal interrupts for Video1 */
	TV_OUT(TV_INTR_ENABLE, 0x5);
	tvout_msm_state->disp_powered_up = TRUE;
	/* Enable interrupts when display is on */
	enable_irq(tvout_msm_state->irq);

error:
	return ret;
}