cregit-Linux how code gets into the kernel

Release 4.11 drivers/gpu/drm/gma500/tc35876x-dsi-lvds.c

/*
 * Copyright © 2011 Intel Corporation
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice (including the next
 * paragraph) shall be included in all copies or substantial portions of the
 * Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

#include "mdfld_dsi_dpi.h"
#include "mdfld_output.h"
#include "mdfld_dsi_pkg_sender.h"
#include "tc35876x-dsi-lvds.h"
#include <linux/i2c/tc35876x.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/intel_scu_ipc.h>


static struct i2c_client *tc35876x_client;

static struct i2c_client *cmi_lcd_i2c_client;


#define FLD_MASK(start, end)	(((1 << ((start) - (end) + 1)) - 1) << (end))

#define FLD_VAL(val, start, end) (((val) << (end)) & FLD_MASK(start, end))

/* DSI D-PHY Layer Registers */

#define D0W_DPHYCONTTX		0x0004

#define CLW_DPHYCONTRX		0x0020

#define D0W_DPHYCONTRX		0x0024

#define D1W_DPHYCONTRX		0x0028

#define D2W_DPHYCONTRX		0x002C

#define D3W_DPHYCONTRX		0x0030

#define COM_DPHYCONTRX		0x0038

#define CLW_CNTRL		0x0040

#define D0W_CNTRL		0x0044

#define D1W_CNTRL		0x0048

#define D2W_CNTRL		0x004C

#define D3W_CNTRL		0x0050

#define DFTMODE_CNTRL		0x0054

/* DSI PPI Layer Registers */

#define PPI_STARTPPI		0x0104

#define PPI_BUSYPPI		0x0108

#define PPI_LINEINITCNT		0x0110

#define PPI_LPTXTIMECNT		0x0114

#define PPI_LANEENABLE		0x0134

#define PPI_TX_RX_TA		0x013C

#define PPI_CLS_ATMR		0x0140

#define PPI_D0S_ATMR		0x0144

#define PPI_D1S_ATMR		0x0148

#define PPI_D2S_ATMR		0x014C

#define PPI_D3S_ATMR		0x0150

#define PPI_D0S_CLRSIPOCOUNT	0x0164

#define PPI_D1S_CLRSIPOCOUNT	0x0168

#define PPI_D2S_CLRSIPOCOUNT	0x016C

#define PPI_D3S_CLRSIPOCOUNT	0x0170

#define CLS_PRE			0x0180

#define D0S_PRE			0x0184

#define D1S_PRE			0x0188

#define D2S_PRE			0x018C

#define D3S_PRE			0x0190

#define CLS_PREP		0x01A0

#define D0S_PREP		0x01A4

#define D1S_PREP		0x01A8

#define D2S_PREP		0x01AC

#define D3S_PREP		0x01B0

#define CLS_ZERO		0x01C0

#define D0S_ZERO		0x01C4

#define D1S_ZERO		0x01C8

#define D2S_ZERO		0x01CC

#define D3S_ZERO		0x01D0

#define PPI_CLRFLG		0x01E0

#define PPI_CLRSIPO		0x01E4

#define HSTIMEOUT		0x01F0

#define HSTIMEOUTENABLE		0x01F4

/* DSI Protocol Layer Registers */

#define DSI_STARTDSI		0x0204

#define DSI_BUSYDSI		0x0208

#define DSI_LANEENABLE		0x0210

#define DSI_LANESTATUS0		0x0214

#define DSI_LANESTATUS1		0x0218

#define DSI_INTSTATUS		0x0220

#define DSI_INTMASK		0x0224

#define DSI_INTCLR		0x0228

#define DSI_LPTXTO		0x0230

/* DSI General Registers */

#define DSIERRCNT		0x0300

/* DSI Application Layer Registers */

#define APLCTRL			0x0400

#define RDPKTLN			0x0404

/* Video Path Registers */

#define VPCTRL			0x0450

#define HTIM1			0x0454

#define HTIM2			0x0458

#define VTIM1			0x045C

#define VTIM2			0x0460

#define VFUEN			0x0464

/* LVDS Registers */

#define LVMX0003		0x0480

#define LVMX0407		0x0484

#define LVMX0811		0x0488

#define LVMX1215		0x048C

#define LVMX1619		0x0490

#define LVMX2023		0x0494

#define LVMX2427		0x0498

#define LVCFG			0x049C

#define LVPHY0			0x04A0

#define LVPHY1			0x04A4

/* System Registers */

#define SYSSTAT			0x0500

#define SYSRST			0x0504

/* GPIO Registers */
/*#define GPIOC                 0x0520*/

#define GPIOO			0x0524

#define GPIOI			0x0528

/* I2C Registers */

#define I2CTIMCTRL		0x0540

#define I2CMADDR		0x0544

#define WDATAQ			0x0548

#define RDATAQ			0x054C

/* Chip/Rev Registers */

#define IDREG			0x0580

/* Debug Registers */

#define DEBUG00			0x05A0

#define DEBUG01			0x05A4

/* Panel CABC registers */

#define PANEL_PWM_CONTROL	0x90

#define PANEL_FREQ_DIVIDER_HI	0x91

#define PANEL_FREQ_DIVIDER_LO	0x92

#define PANEL_DUTY_CONTROL	0x93

#define PANEL_MODIFY_RGB	0x94

#define PANEL_FRAMERATE_CONTROL	0x96

#define PANEL_PWM_MIN		0x97

#define PANEL_PWM_REF		0x98

#define PANEL_PWM_MAX		0x99

#define PANEL_ALLOW_DISTORT	0x9A

#define PANEL_BYPASS_PWMI	0x9B

/* Panel color management registers */

#define PANEL_CM_ENABLE		0x700

#define PANEL_CM_HUE		0x701

#define PANEL_CM_SATURATION	0x702

#define PANEL_CM_INTENSITY	0x703

#define PANEL_CM_BRIGHTNESS	0x704

#define PANEL_CM_CE_ENABLE	0x705

#define PANEL_CM_PEAK_EN	0x710

#define PANEL_CM_GAIN		0x711

#define PANEL_CM_HUETABLE_START	0x730

#define PANEL_CM_HUETABLE_END	0x747 
/* inclusive */

/* Input muxing for registers LVMX0003...LVMX2427 */
enum {
	
INPUT_R0,	/* 0 */
	
INPUT_R1,
	
INPUT_R2,
	
INPUT_R3,
	
INPUT_R4,
	
INPUT_R5,
	
INPUT_R6,
	
INPUT_R7,
	
INPUT_G0,	/* 8 */
	
INPUT_G1,
	
INPUT_G2,
	
INPUT_G3,
	
INPUT_G4,
	
INPUT_G5,
	
INPUT_G6,
	
INPUT_G7,
	
INPUT_B0,	/* 16 */
	
INPUT_B1,
	
INPUT_B2,
	
INPUT_B3,
	
INPUT_B4,
	
INPUT_B5,
	
INPUT_B6,
	
INPUT_B7,
	
INPUT_HSYNC,	/* 24 */
	
INPUT_VSYNC,
	
INPUT_DE,
	
LOGIC_0,
	/* 28...31 undefined */
};


#define INPUT_MUX(lvmx03, lvmx02, lvmx01, lvmx00)		\
	(FLD_VAL(lvmx03, 29, 24) | FLD_VAL(lvmx02, 20, 16) |    \
        FLD_VAL(lvmx01, 12, 8) | FLD_VAL(lvmx00, 4, 0))

/**
 * tc35876x_regw - Write DSI-LVDS bridge register using I2C
 * @client: struct i2c_client to use
 * @reg: register address
 * @value: value to write
 *
 * Returns 0 on success, or a negative error value.
 */

static int tc35876x_regw(struct i2c_client *client, u16 reg, u32 value) { int r; u8 tx_data[] = { /* NOTE: Register address big-endian, data little-endian. */ (reg >> 8) & 0xff, reg & 0xff, value & 0xff, (value >> 8) & 0xff, (value >> 16) & 0xff, (value >> 24) & 0xff, }; struct i2c_msg msgs[] = { { .addr = client->addr, .flags = 0, .buf = tx_data, .len = ARRAY_SIZE(tx_data), }, }; r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (r < 0) { dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x error %d\n", __func__, reg, value, r); return r; } if (r < ARRAY_SIZE(msgs)) { dev_err(&client->dev, "%s: reg 0x%04x val 0x%08x msgs %d\n", __func__, reg, value, r); return -EAGAIN; } dev_dbg(&client->dev, "%s: reg 0x%04x val 0x%08x\n", __func__, reg, value); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov198100.00%1100.00%
Total198100.00%1100.00%

/** * tc35876x_regr - Read DSI-LVDS bridge register using I2C * @client: struct i2c_client to use * @reg: register address * @value: pointer for storing the value * * Returns 0 on success, or a negative error value. */
static int tc35876x_regr(struct i2c_client *client, u16 reg, u32 *value) { int r; u8 tx_data[] = { (reg >> 8) & 0xff, reg & 0xff, }; u8 rx_data[4]; struct i2c_msg msgs[] = { { .addr = client->addr, .flags = 0, .buf = tx_data, .len = ARRAY_SIZE(tx_data), }, { .addr = client->addr, .flags = I2C_M_RD, .buf = rx_data, .len = ARRAY_SIZE(rx_data), }, }; r = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs)); if (r < 0) { dev_err(&client->dev, "%s: reg 0x%04x error %d\n", __func__, reg, r); return r; } if (r < ARRAY_SIZE(msgs)) { dev_err(&client->dev, "%s: reg 0x%04x msgs %d\n", __func__, reg, r); return -EAGAIN; } *value = rx_data[0] << 24 | rx_data[1] << 16 | rx_data[2] << 8 | rx_data[3]; dev_dbg(&client->dev, "%s: reg 0x%04x value 0x%08x\n", __func__, reg, *value); return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov229100.00%1100.00%
Total229100.00%1100.00%


void tc35876x_set_bridge_reset_state(struct drm_device *dev, int state) { struct tc35876x_platform_data *pdata; if (WARN(!tc35876x_client, "%s called before probe", __func__)) return; dev_dbg(&tc35876x_client->dev, "%s: state %d\n", __func__, state); pdata = dev_get_platdata(&tc35876x_client->dev); if (pdata->gpio_bridge_reset == -1) return; if (state) { gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); mdelay(10); } else { /* Pull MIPI Bridge reset pin to Low */ gpio_set_value_cansleep(pdata->gpio_bridge_reset, 0); mdelay(20); /* Pull MIPI Bridge reset pin to High */ gpio_set_value_cansleep(pdata->gpio_bridge_reset, 1); mdelay(40); } }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov118100.00%1100.00%
Total118100.00%1100.00%


void tc35876x_configure_lvds_bridge(struct drm_device *dev) { struct i2c_client *i2c = tc35876x_client; u32 ppi_lptxtimecnt; u32 txtagocnt; u32 txtasurecnt; u32 id; if (WARN(!tc35876x_client, "%s called before probe", __func__)) return; dev_dbg(&tc35876x_client->dev, "%s\n", __func__); if (!tc35876x_regr(i2c, IDREG, &id)) dev_info(&tc35876x_client->dev, "tc35876x ID 0x%08x\n", id); else dev_err(&tc35876x_client->dev, "Cannot read ID\n"); ppi_lptxtimecnt = 4; txtagocnt = (5 * ppi_lptxtimecnt - 3) / 4; txtasurecnt = 3 * ppi_lptxtimecnt / 2; tc35876x_regw(i2c, PPI_TX_RX_TA, FLD_VAL(txtagocnt, 26, 16) | FLD_VAL(txtasurecnt, 10, 0)); tc35876x_regw(i2c, PPI_LPTXTIMECNT, FLD_VAL(ppi_lptxtimecnt, 10, 0)); tc35876x_regw(i2c, PPI_D0S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); tc35876x_regw(i2c, PPI_D1S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); tc35876x_regw(i2c, PPI_D2S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); tc35876x_regw(i2c, PPI_D3S_CLRSIPOCOUNT, FLD_VAL(1, 5, 0)); /* Enabling MIPI & PPI lanes, Enable 4 lanes */ tc35876x_regw(i2c, PPI_LANEENABLE, BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); tc35876x_regw(i2c, DSI_LANEENABLE, BIT(4) | BIT(3) | BIT(2) | BIT(1) | BIT(0)); tc35876x_regw(i2c, PPI_STARTPPI, BIT(0)); tc35876x_regw(i2c, DSI_STARTDSI, BIT(0)); /* Setting LVDS output frequency */ tc35876x_regw(i2c, LVPHY0, FLD_VAL(1, 20, 16) | FLD_VAL(2, 15, 14) | FLD_VAL(6, 4, 0)); /* 0x00048006 */ /* Setting video panel control register,0x00000120 VTGen=ON ?!?!? */ tc35876x_regw(i2c, VPCTRL, BIT(8) | BIT(5)); /* Horizontal back porch and horizontal pulse width. 0x00280028 */ tc35876x_regw(i2c, HTIM1, FLD_VAL(40, 24, 16) | FLD_VAL(40, 8, 0)); /* Horizontal front porch and horizontal active video size. 0x00500500*/ tc35876x_regw(i2c, HTIM2, FLD_VAL(80, 24, 16) | FLD_VAL(1280, 10, 0)); /* Vertical back porch and vertical sync pulse width. 0x000e000a */ tc35876x_regw(i2c, VTIM1, FLD_VAL(14, 23, 16) | FLD_VAL(10, 7, 0)); /* Vertical front porch and vertical display size. 0x000e0320 */ tc35876x_regw(i2c, VTIM2, FLD_VAL(14, 23, 16) | FLD_VAL(800, 10, 0)); /* Set above HTIM1, HTIM2, VTIM1, and VTIM2 at next VSYNC. */ tc35876x_regw(i2c, VFUEN, BIT(0)); /* Soft reset LCD controller. */ tc35876x_regw(i2c, SYSRST, BIT(2)); /* LVDS-TX input muxing */ tc35876x_regw(i2c, LVMX0003, INPUT_MUX(INPUT_R5, INPUT_R4, INPUT_R3, INPUT_R2)); tc35876x_regw(i2c, LVMX0407, INPUT_MUX(INPUT_G2, INPUT_R7, INPUT_R1, INPUT_R6)); tc35876x_regw(i2c, LVMX0811, INPUT_MUX(INPUT_G1, INPUT_G0, INPUT_G4, INPUT_G3)); tc35876x_regw(i2c, LVMX1215, INPUT_MUX(INPUT_B2, INPUT_G7, INPUT_G6, INPUT_G5)); tc35876x_regw(i2c, LVMX1619, INPUT_MUX(INPUT_B4, INPUT_B3, INPUT_B1, INPUT_B0)); tc35876x_regw(i2c, LVMX2023, INPUT_MUX(LOGIC_0, INPUT_B7, INPUT_B6, INPUT_B5)); tc35876x_regw(i2c, LVMX2427, INPUT_MUX(INPUT_R0, INPUT_DE, INPUT_VSYNC, INPUT_HSYNC)); /* Enable LVDS transmitter. */ tc35876x_regw(i2c, LVCFG, BIT(0)); /* Clear notifications. Don't write reserved bits. Was write 0xffffffff * to 0x0288, must be in error?! */ tc35876x_regw(i2c, DSI_INTCLR, FLD_MASK(31, 30) | FLD_MASK(22, 0)); }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov654100.00%1100.00%
Total654100.00%1100.00%

#define GPIOPWMCTRL 0x38F #define PWM0CLKDIV0 0x62 /* low byte */ #define PWM0CLKDIV1 0x61 /* high byte */ #define SYSTEMCLK 19200000UL /* 19.2 MHz */ #define PWM_FREQUENCY 9600 /* Hz */ /* f = baseclk / (clkdiv + 1) => clkdiv = (baseclk - f) / f */
static inline u16 calc_clkdiv(unsigned long baseclk, unsigned int f) { return (baseclk - f) / f; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov24100.00%1100.00%
Total24100.00%1100.00%


static void tc35876x_brightness_init(struct drm_device *dev) { int ret; u8 pwmctrl; u16 clkdiv; /* Make sure the PWM reference is the 19.2 MHz system clock. Read first * instead of setting directly to catch potential conflicts between PWM * users. */ ret = intel_scu_ipc_ioread8(GPIOPWMCTRL, &pwmctrl); if (ret || pwmctrl != 0x01) { if (ret) dev_err(&dev->pdev->dev, "GPIOPWMCTRL read failed\n"); else dev_warn(&dev->pdev->dev, "GPIOPWMCTRL was not set to system clock (pwmctrl = 0x%02x)\n", pwmctrl); ret = intel_scu_ipc_iowrite8(GPIOPWMCTRL, 0x01); if (ret) dev_err(&dev->pdev->dev, "GPIOPWMCTRL set failed\n"); } clkdiv = calc_clkdiv(SYSTEMCLK, PWM_FREQUENCY); ret = intel_scu_ipc_iowrite8(PWM0CLKDIV1, (clkdiv >> 8) & 0xff); if (!ret) ret = intel_scu_ipc_iowrite8(PWM0CLKDIV0, clkdiv & 0xff); if (ret) dev_err(&dev->pdev->dev, "PWM0CLKDIV set failed\n"); else dev_dbg(&dev->pdev->dev, "PWM0CLKDIV set to 0x%04x (%d Hz)\n", clkdiv, PWM_FREQUENCY); }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov170100.00%1100.00%
Total170100.00%1100.00%

#define PWM0DUTYCYCLE 0x67
void tc35876x_brightness_control(struct drm_device *dev, int level) { int ret; u8 duty_val; u8 panel_duty_val; level = clamp(level, 0, MDFLD_DSI_BRIGHTNESS_MAX_LEVEL); /* PWM duty cycle 0x00...0x63 corresponds to 0...99% */ duty_val = level * 0x63 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL; /* I won't pretend to understand this formula. The panel spec is quite * bad engrish. */ panel_duty_val = (2 * level - 100) * 0xA9 / MDFLD_DSI_BRIGHTNESS_MAX_LEVEL + 0x56; ret = intel_scu_ipc_iowrite8(PWM0DUTYCYCLE, duty_val); if (ret) dev_err(&tc35876x_client->dev, "%s: ipc write fail\n", __func__); if (cmi_lcd_i2c_client) { ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, PANEL_PWM_MAX, panel_duty_val); if (ret < 0) dev_err(&cmi_lcd_i2c_client->dev, "%s: i2c write failed\n", __func__); } }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov119100.00%1100.00%
Total119100.00%1100.00%


void tc35876x_toshiba_bridge_panel_off(struct drm_device *dev) { struct tc35876x_platform_data *pdata; if (WARN(!tc35876x_client, "%s called before probe", __func__)) return; dev_dbg(&tc35876x_client->dev, "%s\n", __func__); pdata = dev_get_platdata(&tc35876x_client->dev); if (pdata->gpio_panel_bl_en != -1) gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 0); if (pdata->gpio_panel_vadd != -1) gpio_set_value_cansleep(pdata->gpio_panel_vadd, 0); }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov86100.00%1100.00%
Total86100.00%1100.00%


void tc35876x_toshiba_bridge_panel_on(struct drm_device *dev) { struct tc35876x_platform_data *pdata; struct drm_psb_private *dev_priv = dev->dev_private; if (WARN(!tc35876x_client, "%s called before probe", __func__)) return; dev_dbg(&tc35876x_client->dev, "%s\n", __func__); pdata = dev_get_platdata(&tc35876x_client->dev); if (pdata->gpio_panel_vadd != -1) { gpio_set_value_cansleep(pdata->gpio_panel_vadd, 1); msleep(260); } if (cmi_lcd_i2c_client) { int ret; dev_dbg(&cmi_lcd_i2c_client->dev, "setting TCON\n"); /* Bit 4 is average_saving. Setting it to 1, the brightness is * referenced to the average of the frame content. 0 means * reference to the maximum of frame contents. Bits 3:0 are * allow_distort. When set to a nonzero value, all color values * between 255-allow_distort*2 and 255 are mapped to the * 255-allow_distort*2 value. */ ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, PANEL_ALLOW_DISTORT, 0x10); if (ret < 0) dev_err(&cmi_lcd_i2c_client->dev, "i2c write failed (%d)\n", ret); ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, PANEL_BYPASS_PWMI, 0); if (ret < 0) dev_err(&cmi_lcd_i2c_client->dev, "i2c write failed (%d)\n", ret); /* Set minimum brightness value - this is tunable */ ret = i2c_smbus_write_byte_data(cmi_lcd_i2c_client, PANEL_PWM_MIN, 0x35); if (ret < 0) dev_err(&cmi_lcd_i2c_client->dev, "i2c write failed (%d)\n", ret); } if (pdata->gpio_panel_bl_en != -1) gpio_set_value_cansleep(pdata->gpio_panel_bl_en, 1); tc35876x_brightness_control(dev, dev_priv->brightness_adjusted); }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov219100.00%1100.00%
Total219100.00%1100.00%


static struct drm_display_mode *tc35876x_get_config_mode(struct drm_device *dev) { struct drm_display_mode *mode; dev_dbg(&dev->pdev->dev, "%s\n", __func__); mode = kzalloc(sizeof(*mode), GFP_KERNEL); if (!mode) return NULL; /* FIXME: do this properly. */ mode->hdisplay = 1280; mode->vdisplay = 800; mode->hsync_start = 1360; mode->hsync_end = 1400; mode->htotal = 1440; mode->vsync_start = 814; mode->vsync_end = 824; mode->vtotal = 838; mode->clock = 33324 << 1; dev_info(&dev->pdev->dev, "hdisplay(w) = %d\n", mode->hdisplay); dev_info(&dev->pdev->dev, "vdisplay(h) = %d\n", mode->vdisplay); dev_info(&dev->pdev->dev, "HSS = %d\n", mode->hsync_start); dev_info(&dev->pdev->dev, "HSE = %d\n", mode->hsync_end); dev_info(&dev->pdev->dev, "htotal = %d\n", mode->htotal); dev_info(&dev->pdev->dev, "VSS = %d\n", mode->vsync_start); dev_info(&dev->pdev->dev, "VSE = %d\n", mode->vsync_end); dev_info(&dev->pdev->dev, "vtotal = %d\n", mode->vtotal); dev_info(&dev->pdev->dev, "clock = %d\n", mode->clock); drm_mode_set_name(mode); drm_mode_set_crtcinfo(mode, 0); mode->type |= DRM_MODE_TYPE_PREFERRED; return mode; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov275100.00%1100.00%
Total275100.00%1100.00%

/* DV1 Active area 216.96 x 135.6 mm */ #define DV1_PANEL_WIDTH 217 #define DV1_PANEL_HEIGHT 136
static int tc35876x_get_panel_info(struct drm_device *dev, int pipe, struct panel_info *pi) { if (!dev || !pi) return -EINVAL; pi->width_mm = DV1_PANEL_WIDTH; pi->height_mm = DV1_PANEL_HEIGHT; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov46100.00%1100.00%
Total46100.00%1100.00%


static int tc35876x_bridge_probe(struct i2c_client *client, const struct i2c_device_id *id) { struct tc35876x_platform_data *pdata; dev_info(&client->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", __func__); return -ENODEV; } pdata = dev_get_platdata(&client->dev); if (!pdata) { dev_err(&client->dev, "%s: no platform data\n", __func__); return -ENODEV; } if (pdata->gpio_bridge_reset != -1) { gpio_request(pdata->gpio_bridge_reset, "tc35876x bridge reset"); gpio_direction_output(pdata->gpio_bridge_reset, 0); } if (pdata->gpio_panel_bl_en != -1) { gpio_request(pdata->gpio_panel_bl_en, "tc35876x panel bl en"); gpio_direction_output(pdata->gpio_panel_bl_en, 0); } if (pdata->gpio_panel_vadd != -1) { gpio_request(pdata->gpio_panel_vadd, "tc35876x panel vadd"); gpio_direction_output(pdata->gpio_panel_vadd, 0); } tc35876x_client = client; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov191100.00%1100.00%
Total191100.00%1100.00%


static int tc35876x_bridge_remove(struct i2c_client *client) { struct tc35876x_platform_data *pdata = dev_get_platdata(&client->dev); dev_dbg(&client->dev, "%s\n", __func__); if (pdata->gpio_bridge_reset != -1) gpio_free(pdata->gpio_bridge_reset); if (pdata->gpio_panel_bl_en != -1) gpio_free(pdata->gpio_panel_bl_en); if (pdata->gpio_panel_vadd != -1) gpio_free(pdata->gpio_panel_vadd); tc35876x_client = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov91100.00%1100.00%
Total91100.00%1100.00%

static const struct i2c_device_id tc35876x_bridge_id[] = { { "i2c_disp_brig", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, tc35876x_bridge_id); static struct i2c_driver tc35876x_bridge_i2c_driver = { .driver = { .name = "i2c_disp_brig", }, .id_table = tc35876x_bridge_id, .probe = tc35876x_bridge_probe, .remove = tc35876x_bridge_remove, }; /* LCD panel I2C */
static int cmi_lcd_i2c_probe(struct i2c_client *client, const struct i2c_device_id *id) { dev_info(&client->dev, "%s\n", __func__); if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { dev_err(&client->dev, "%s: i2c_check_functionality() failed\n", __func__); return -ENODEV; } cmi_lcd_i2c_client = client; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov66100.00%1100.00%
Total66100.00%1100.00%


static int cmi_lcd_i2c_remove(struct i2c_client *client) { dev_dbg(&client->dev, "%s\n", __func__); cmi_lcd_i2c_client = NULL; return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov30100.00%1100.00%
Total30100.00%1100.00%

static const struct i2c_device_id cmi_lcd_i2c_id[] = { { "cmi-lcd", 0 }, { } }; MODULE_DEVICE_TABLE(i2c, cmi_lcd_i2c_id); static struct i2c_driver cmi_lcd_i2c_driver = { .driver = { .name = "cmi-lcd", }, .id_table = cmi_lcd_i2c_id, .probe = cmi_lcd_i2c_probe, .remove = cmi_lcd_i2c_remove, }; /* HACK to create I2C device while it's not created by platform code */ #define CMI_LCD_I2C_ADAPTER 2 #define CMI_LCD_I2C_ADDR 0x60
static int cmi_lcd_hack_create_device(void) { struct i2c_adapter *adapter; struct i2c_client *client; struct i2c_board_info info = { .type = "cmi-lcd", .addr = CMI_LCD_I2C_ADDR, }; pr_debug("%s\n", __func__); adapter = i2c_get_adapter(CMI_LCD_I2C_ADAPTER); if (!adapter) { pr_err("%s: i2c_get_adapter(%d) failed\n", __func__, CMI_LCD_I2C_ADAPTER); return -EINVAL; } client = i2c_new_device(adapter, &info); if (!client) { pr_err("%s: i2c_new_device() failed\n", __func__); i2c_put_adapter(adapter); return -EINVAL; } return 0; }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov104100.00%1100.00%
Total104100.00%1100.00%

static const struct drm_encoder_helper_funcs tc35876x_encoder_helper_funcs = { .dpms = mdfld_dsi_dpi_dpms, .mode_fixup = mdfld_dsi_dpi_mode_fixup, .prepare = mdfld_dsi_dpi_prepare, .mode_set = mdfld_dsi_dpi_mode_set, .commit = mdfld_dsi_dpi_commit, }; static const struct drm_encoder_funcs tc35876x_encoder_funcs = { .destroy = drm_encoder_cleanup, }; const struct panel_funcs mdfld_tc35876x_funcs = { .encoder_funcs = &tc35876x_encoder_funcs, .encoder_helper_funcs = &tc35876x_encoder_helper_funcs, .get_config_mode = tc35876x_get_config_mode, .get_panel_info = tc35876x_get_panel_info, };
void tc35876x_init(struct drm_device *dev) { int r; dev_dbg(&dev->pdev->dev, "%s\n", __func__); cmi_lcd_hack_create_device(); r = i2c_add_driver(&cmi_lcd_i2c_driver); if (r < 0) dev_err(&dev->pdev->dev, "%s: i2c_add_driver() for %s failed (%d)\n", __func__, cmi_lcd_i2c_driver.driver.name, r); r = i2c_add_driver(&tc35876x_bridge_i2c_driver); if (r < 0) dev_err(&dev->pdev->dev, "%s: i2c_add_driver() for %s failed (%d)\n", __func__, tc35876x_bridge_i2c_driver.driver.name, r); tc35876x_brightness_init(dev); }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov107100.00%1100.00%
Total107100.00%1100.00%


void tc35876x_exit(void) { pr_debug("%s\n", __func__); i2c_del_driver(&tc35876x_bridge_i2c_driver); if (cmi_lcd_i2c_client) i2c_del_driver(&cmi_lcd_i2c_driver); }

Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov30100.00%1100.00%
Total30100.00%1100.00%


Overall Contributors

PersonTokensPropCommitsCommitProp
Kirill A. Shutemov3575100.00%1100.00%
Total3575100.00%1100.00%
Information contained on this website is for historical information purposes only and does not indicate or represent copyright ownership.
Created with cregit.