drm/panel: Changes for v3.19-rc1
This contains support for a couple of new panels, updates for some GPIO API changes and a bunch of updates to the MIPI DSI support that should make it easier to write panel drivers in the future. -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABAgAGBQJUZKsmAAoJEN0jrNd/PrOhvoQP/Ryl8OHSEOB6vNxn7cmz3nQf 0l+2Q3V3qpJALC3Dlm57kSF1760mHNjPuwiVLhjINn5zcDS4kB3Llgx/dmAzgTZA Ikm8iDgcOmlBUBE1W5YuzdSCXJK8Eth9JQiA4yQVS0RWi+WEClwb+F7KBLi+9Ep3 1C3qURrBAfe9DRzU4GswrsCzBQACCKH8f+2OcYeFMW0eMa7ejHNs+n0wi6lMLvLn JrxEuMBKWdXbM2sw4UXvpVZm3CTh8dJtXBkpwOBK75XhY9DSsrqmbdk0qKIDCY+y JB/5UTU2sg37ZFnvhFoHN10AtXWnGbwS2iCitNSmKaBOARVbcoWk9pJtR3AHc44c cpLVTsJgZStYZAydtVZKQDJWLNTnTMtyLPcy9eq6kLMc8sVe930U8IsGQyihyyUU cSDP8Z6THZ2zHqfDnmogjm8XWsUa+LimNwAgm5oub8JKxdqGb49J8ry+Ny4a19cS MgqVZE85K9aF7e/VxeGFiIpUb5ax5bLQxrcpVJg/d2TFuftNBslmL3FOkvEbwrLM WS9KJ8e8VIRNoI5dtemfx0+LGlLwoPaUWSeWpb8OxUAuy6e5NabazkFQuCb5E+HM JLqnMFCCVvwtGyr+DrFiF4ye8ZTZNcFcdidgB4mr9D5k7RksyeZTT4vz13y2JyAr VcfbBQICIQzn91osEetJ =+xMK -----END PGP SIGNATURE----- Merge tag 'drm/panel/for-3.19-rc1' of git://people.freedesktop.org/~tagr/linux into drm-next drm/panel: Changes for v3.19-rc1 This contains support for a couple of new panels, updates for some GPIO API changes and a bunch of updates to the MIPI DSI support that should make it easier to write panel drivers in the future. * tag 'drm/panel/for-3.19-rc1' of git://people.freedesktop.org/~tagr/linux: (31 commits) drm/panel: Add Sharp LQ101R1SX01 support drm/dsi: Do not require .owner field to be set drm/dsi: Resolve MIPI DSI device from phandle drm/dsi: Implement DCS set_{column,page}_address commands drm/dsi: Implement DCS {get,set}_pixel_format commands drm/dsi: Implement DCS get_power_mode command drm/dsi: Implement DCS soft_reset command drm/dsi: Implement DCS nop command drm/dsi: Add to DocBook documentation drm/dsi: Implement some standard DCS commands drm/dsi: Implement generic read and write commands drm/panel: s6e8aa0: Use standard MIPI DSI function drm/dsi: Add mipi_dsi_set_maximum_return_packet_size() helper drm/dsi: Constify mipi_dsi_msg drm/dsi: Make mipi_dsi_dcs_{read,write}() symmetrical drm/dsi: Add DSI transfer helper drm/dsi: Add message to packet translator drm/dsi: Introduce packet format helpers drm/panel: s6e8aa0: Fix build warnings on 64-bit drm/panel: ld9040: Fix build warnings on 64-bit ...
This commit is contained in:
commit
8aa3dc3c17
|
@ -2366,6 +2366,12 @@ void intel_crt_init(struct drm_device *dev)
|
|||
!Pdrivers/gpu/drm/drm_dp_mst_topology.c dp mst helper
|
||||
!Iinclude/drm/drm_dp_mst_helper.h
|
||||
!Edrivers/gpu/drm/drm_dp_mst_topology.c
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>MIPI DSI Helper Functions Reference</title>
|
||||
!Pdrivers/gpu/drm/drm_mipi_dsi.c dsi helpers
|
||||
!Iinclude/drm/drm_mipi_dsi.h
|
||||
!Edrivers/gpu/drm/drm_mipi_dsi.c
|
||||
</sect2>
|
||||
<sect2>
|
||||
<title>EDID Helper Functions Reference</title>
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
AU Optronics Corporation 11.6" HD (1366x768) color TFT-LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "auo,b116xw03"
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
|
@ -0,0 +1,7 @@
|
|||
HannStar Display Corp. HSD070PWW1 7.0" WXGA TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "hannstar,hsd070pww1"
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
|
@ -0,0 +1,7 @@
|
|||
Hitachi Ltd. Corporation 9" WVGA (800x480) TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "hit,tx23d38vm0caa"
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
|
@ -0,0 +1,7 @@
|
|||
Innolux Corporation 12.1" WXGA (1280x800) TFT LCD panel
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "innolux,g121i1-l01"
|
||||
|
||||
This binding is compatible with the simple-panel binding, which is specified
|
||||
in simple-panel.txt in this directory.
|
|
@ -0,0 +1,49 @@
|
|||
Sharp Microelectronics 10.1" WQXGA TFT LCD panel
|
||||
|
||||
This panel requires a dual-channel DSI host to operate. It supports two modes:
|
||||
- left-right: each channel drives the left or right half of the screen
|
||||
- even-odd: each channel drives the even or odd lines of the screen
|
||||
|
||||
Each of the DSI channels controls a separate DSI peripheral. The peripheral
|
||||
driven by the first link (DSI-LINK1), left or even, is considered the primary
|
||||
peripheral and controls the device. The 'link2' property contains a phandle
|
||||
to the peripheral driven by the second link (DSI-LINK2, right or odd).
|
||||
|
||||
Note that in video mode the DSI-LINK1 interface always provides the left/even
|
||||
pixels and DSI-LINK2 always provides the right/odd pixels. In command mode it
|
||||
is possible to program either link to drive the left/even or right/odd pixels
|
||||
but for the sake of consistency this binding assumes that the same assignment
|
||||
is chosen as for video mode.
|
||||
|
||||
Required properties:
|
||||
- compatible: should be "sharp,lq101r1sx01"
|
||||
- reg: DSI virtual channel of the peripheral
|
||||
|
||||
Required properties (for DSI-LINK1 only):
|
||||
- link2: phandle to the DSI peripheral on the secondary link. Note that the
|
||||
presence of this property marks the containing node as DSI-LINK1.
|
||||
- power-supply: phandle of the regulator that provides the supply voltage
|
||||
|
||||
Optional properties (for DSI-LINK1 only):
|
||||
- backlight: phandle of the backlight device attached to the panel
|
||||
|
||||
Example:
|
||||
|
||||
dsi@54300000 {
|
||||
panel: panel@0 {
|
||||
compatible = "sharp,lq101r1sx01";
|
||||
reg = <0>;
|
||||
|
||||
link2 = <&secondary>;
|
||||
|
||||
power-supply = <...>;
|
||||
backlight = <...>;
|
||||
};
|
||||
};
|
||||
|
||||
dsi@54400000 {
|
||||
secondary: panel@0 {
|
||||
compatible = "sharp,lq101r1sx01";
|
||||
reg = <0>;
|
||||
};
|
||||
};
|
|
@ -64,8 +64,10 @@ gmt Global Mixed-mode Technology, Inc.
|
|||
google Google, Inc.
|
||||
gumstix Gumstix, Inc.
|
||||
gw Gateworks Corporation
|
||||
hannstar HannStar Display Corporation
|
||||
haoyu Haoyu Microelectronic Co. Ltd.
|
||||
hisilicon Hisilicon Limited.
|
||||
hit Hitachi Ltd.
|
||||
honeywell Honeywell
|
||||
hp Hewlett Packard
|
||||
i2se I2SE GmbH
|
||||
|
|
|
@ -35,6 +35,16 @@
|
|||
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
/**
|
||||
* DOC: dsi helpers
|
||||
*
|
||||
* These functions contain some common logic and helpers to deal with MIPI DSI
|
||||
* peripherals.
|
||||
*
|
||||
* Helpers are provided for a number of standard MIPI DSI command as well as a
|
||||
* subset of the MIPI DCS command set.
|
||||
*/
|
||||
|
||||
static int mipi_dsi_device_match(struct device *dev, struct device_driver *drv)
|
||||
{
|
||||
return of_driver_match_device(dev, drv);
|
||||
|
@ -57,6 +67,29 @@ static struct bus_type mipi_dsi_bus_type = {
|
|||
.pm = &mipi_dsi_device_pm_ops,
|
||||
};
|
||||
|
||||
static int of_device_match(struct device *dev, void *data)
|
||||
{
|
||||
return dev->of_node == data;
|
||||
}
|
||||
|
||||
/**
|
||||
* of_find_mipi_dsi_device_by_node() - find the MIPI DSI device matching a
|
||||
* device tree node
|
||||
* @np: device tree node
|
||||
*
|
||||
* Return: A pointer to the MIPI DSI device corresponding to @np or NULL if no
|
||||
* such device exists (or has not been registered yet).
|
||||
*/
|
||||
struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np)
|
||||
{
|
||||
struct device *dev;
|
||||
|
||||
dev = bus_find_device(&mipi_dsi_bus_type, NULL, np, of_device_match);
|
||||
|
||||
return dev ? to_mipi_dsi_device(dev) : NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(of_find_mipi_dsi_device_by_node);
|
||||
|
||||
static void mipi_dsi_dev_release(struct device *dev)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(dev);
|
||||
|
@ -198,59 +231,351 @@ int mipi_dsi_detach(struct mipi_dsi_device *dsi)
|
|||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_detach);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_write - send DCS write command
|
||||
* @dsi: DSI device
|
||||
* @data: pointer to the command followed by parameters
|
||||
* @len: length of @data
|
||||
*/
|
||||
ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
|
||||
size_t len)
|
||||
static ssize_t mipi_dsi_device_transfer(struct mipi_dsi_device *dsi,
|
||||
struct mipi_dsi_msg *msg)
|
||||
{
|
||||
const struct mipi_dsi_host_ops *ops = dsi->host->ops;
|
||||
|
||||
if (!ops || !ops->transfer)
|
||||
return -ENOSYS;
|
||||
|
||||
if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
|
||||
msg->flags |= MIPI_DSI_MSG_USE_LPM;
|
||||
|
||||
return ops->transfer(dsi->host, msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_packet_format_is_short - check if a packet is of the short format
|
||||
* @type: MIPI DSI data type of the packet
|
||||
*
|
||||
* Return: true if the packet for the given data type is a short packet, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool mipi_dsi_packet_format_is_short(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIPI_DSI_V_SYNC_START:
|
||||
case MIPI_DSI_V_SYNC_END:
|
||||
case MIPI_DSI_H_SYNC_START:
|
||||
case MIPI_DSI_H_SYNC_END:
|
||||
case MIPI_DSI_END_OF_TRANSMISSION:
|
||||
case MIPI_DSI_COLOR_MODE_OFF:
|
||||
case MIPI_DSI_COLOR_MODE_ON:
|
||||
case MIPI_DSI_SHUTDOWN_PERIPHERAL:
|
||||
case MIPI_DSI_TURN_ON_PERIPHERAL:
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM:
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM:
|
||||
case MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE:
|
||||
case MIPI_DSI_DCS_SHORT_WRITE_PARAM:
|
||||
case MIPI_DSI_DCS_READ:
|
||||
case MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_packet_format_is_short);
|
||||
|
||||
/**
|
||||
* mipi_dsi_packet_format_is_long - check if a packet is of the long format
|
||||
* @type: MIPI DSI data type of the packet
|
||||
*
|
||||
* Return: true if the packet for the given data type is a long packet, false
|
||||
* otherwise.
|
||||
*/
|
||||
bool mipi_dsi_packet_format_is_long(u8 type)
|
||||
{
|
||||
switch (type) {
|
||||
case MIPI_DSI_NULL_PACKET:
|
||||
case MIPI_DSI_BLANKING_PACKET:
|
||||
case MIPI_DSI_GENERIC_LONG_WRITE:
|
||||
case MIPI_DSI_DCS_LONG_WRITE:
|
||||
case MIPI_DSI_LOOSELY_PACKED_PIXEL_STREAM_YCBCR20:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR24:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR16:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_30:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_36:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_YCBCR12:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_16:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_18:
|
||||
case MIPI_DSI_PIXEL_STREAM_3BYTE_18:
|
||||
case MIPI_DSI_PACKED_PIXEL_STREAM_24:
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_packet_format_is_long);
|
||||
|
||||
/**
|
||||
* mipi_dsi_create_packet - create a packet from a message according to the
|
||||
* DSI protocol
|
||||
* @packet: pointer to a DSI packet structure
|
||||
* @msg: message to translate into a packet
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
||||
const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
const u8 *tx = msg->tx_buf;
|
||||
|
||||
if (!packet || !msg)
|
||||
return -EINVAL;
|
||||
|
||||
/* do some minimum sanity checking */
|
||||
if (!mipi_dsi_packet_format_is_short(msg->type) &&
|
||||
!mipi_dsi_packet_format_is_long(msg->type))
|
||||
return -EINVAL;
|
||||
|
||||
if (msg->channel > 3)
|
||||
return -EINVAL;
|
||||
|
||||
memset(packet, 0, sizeof(*packet));
|
||||
packet->header[0] = ((msg->channel & 0x3) << 6) | (msg->type & 0x3f);
|
||||
|
||||
/* TODO: compute ECC if hardware support is not available */
|
||||
|
||||
/*
|
||||
* Long write packets contain the word count in header bytes 1 and 2.
|
||||
* The payload follows the header and is word count bytes long.
|
||||
*
|
||||
* Short write packets encode up to two parameters in header bytes 1
|
||||
* and 2.
|
||||
*/
|
||||
if (mipi_dsi_packet_format_is_long(msg->type)) {
|
||||
packet->header[1] = (msg->tx_len >> 0) & 0xff;
|
||||
packet->header[2] = (msg->tx_len >> 8) & 0xff;
|
||||
|
||||
packet->payload_length = msg->tx_len;
|
||||
packet->payload = tx;
|
||||
} else {
|
||||
packet->header[1] = (msg->tx_len > 0) ? tx[0] : 0;
|
||||
packet->header[2] = (msg->tx_len > 1) ? tx[1] : 0;
|
||||
}
|
||||
|
||||
packet->size = sizeof(packet->header) + packet->payload_length;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_create_packet);
|
||||
|
||||
/*
|
||||
* mipi_dsi_set_maximum_return_packet_size() - specify the maximum size of the
|
||||
* the payload in a long packet transmitted from the peripheral back to the
|
||||
* host processor
|
||||
* @dsi: DSI peripheral device
|
||||
* @value: the maximum size of the payload
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
|
||||
u16 value)
|
||||
{
|
||||
u8 tx[2] = { value & 0xff, value >> 8 };
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
|
||||
.tx_len = sizeof(tx),
|
||||
.tx_buf = tx,
|
||||
};
|
||||
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_set_maximum_return_packet_size);
|
||||
|
||||
/**
|
||||
* mipi_dsi_generic_write() - transmit data using a generic write packet
|
||||
* @dsi: DSI peripheral device
|
||||
* @payload: buffer containing the payload
|
||||
* @size: size of payload buffer
|
||||
*
|
||||
* This function will automatically choose the right data type depending on
|
||||
* the payload length.
|
||||
*
|
||||
* Return: The number of bytes transmitted on success or a negative error code
|
||||
* on failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
|
||||
size_t size)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.tx_buf = payload,
|
||||
.tx_len = size
|
||||
};
|
||||
|
||||
switch (size) {
|
||||
case 0:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_0_PARAM;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_1_PARAM;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_GENERIC_SHORT_WRITE_2_PARAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg.type = MIPI_DSI_GENERIC_LONG_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_generic_write);
|
||||
|
||||
/**
|
||||
* mipi_dsi_generic_read() - receive data using a generic read packet
|
||||
* @dsi: DSI peripheral device
|
||||
* @params: buffer containing the request parameters
|
||||
* @num_params: number of request parameters
|
||||
* @data: buffer in which to return the received data
|
||||
* @size: size of receive buffer
|
||||
*
|
||||
* This function will automatically choose the right data type depending on
|
||||
* the number of parameters passed in.
|
||||
*
|
||||
* Return: The number of bytes successfully read or a negative error code on
|
||||
* failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
|
||||
size_t num_params, void *data, size_t size)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.tx_len = num_params,
|
||||
.tx_buf = params,
|
||||
.rx_len = size,
|
||||
.rx_buf = data
|
||||
};
|
||||
|
||||
switch (num_params) {
|
||||
case 0:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_0_PARAM;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_1_PARAM;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_GENERIC_READ_REQUEST_2_PARAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_generic_read);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_write_buffer() - transmit a DCS command with payload
|
||||
* @dsi: DSI peripheral device
|
||||
* @data: buffer containing data to be transmitted
|
||||
* @len: size of transmission buffer
|
||||
*
|
||||
* This function will automatically choose the right data type depending on
|
||||
* the command payload length.
|
||||
*
|
||||
* Return: The number of bytes successfully transmitted or a negative error
|
||||
* code on failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.tx_buf = data,
|
||||
.tx_len = len
|
||||
};
|
||||
|
||||
if (!ops || !ops->transfer)
|
||||
return -ENOSYS;
|
||||
|
||||
switch (len) {
|
||||
case 0:
|
||||
return -EINVAL;
|
||||
|
||||
case 1:
|
||||
msg.type = MIPI_DSI_DCS_SHORT_WRITE;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
msg.type = MIPI_DSI_DCS_SHORT_WRITE_PARAM;
|
||||
break;
|
||||
|
||||
default:
|
||||
msg.type = MIPI_DSI_DCS_LONG_WRITE;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
|
||||
msg.flags = MIPI_DSI_MSG_USE_LPM;
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_write_buffer);
|
||||
|
||||
return ops->transfer(dsi->host, &msg);
|
||||
/**
|
||||
* mipi_dsi_dcs_write() - send DCS write command
|
||||
* @dsi: DSI peripheral device
|
||||
* @cmd: DCS command
|
||||
* @data: buffer containing the command payload
|
||||
* @len: command payload length
|
||||
*
|
||||
* This function will automatically choose the right data type depending on
|
||||
* the command payload length.
|
||||
*
|
||||
* Return: The number of bytes successfully transmitted or a negative error
|
||||
* code on failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
|
||||
const void *data, size_t len)
|
||||
{
|
||||
ssize_t err;
|
||||
size_t size;
|
||||
u8 *tx;
|
||||
|
||||
if (len > 0) {
|
||||
size = 1 + len;
|
||||
|
||||
tx = kmalloc(size, GFP_KERNEL);
|
||||
if (!tx)
|
||||
return -ENOMEM;
|
||||
|
||||
/* concatenate the DCS command byte and the payload */
|
||||
tx[0] = cmd;
|
||||
memcpy(&tx[1], data, len);
|
||||
} else {
|
||||
tx = &cmd;
|
||||
size = 1;
|
||||
}
|
||||
|
||||
err = mipi_dsi_dcs_write_buffer(dsi, tx, size);
|
||||
|
||||
if (len > 0)
|
||||
kfree(tx);
|
||||
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_write);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_read - send DCS read request command
|
||||
* @dsi: DSI device
|
||||
* @cmd: DCS read command
|
||||
* @data: pointer to read buffer
|
||||
* @len: length of @data
|
||||
* mipi_dsi_dcs_read() - send DCS read request command
|
||||
* @dsi: DSI peripheral device
|
||||
* @cmd: DCS command
|
||||
* @data: buffer in which to receive data
|
||||
* @len: size of receive buffer
|
||||
*
|
||||
* Function returns number of read bytes or error code.
|
||||
* Return: The number of bytes read or a negative error code on failure.
|
||||
*/
|
||||
ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
|
||||
size_t len)
|
||||
{
|
||||
const struct mipi_dsi_host_ops *ops = dsi->host->ops;
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.type = MIPI_DSI_DCS_READ,
|
||||
|
@ -260,16 +585,283 @@ ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
|
|||
.rx_len = len
|
||||
};
|
||||
|
||||
if (!ops || !ops->transfer)
|
||||
return -ENOSYS;
|
||||
|
||||
if (dsi->mode_flags & MIPI_DSI_MODE_LPM)
|
||||
msg.flags = MIPI_DSI_MSG_USE_LPM;
|
||||
|
||||
return ops->transfer(dsi->host, &msg);
|
||||
return mipi_dsi_device_transfer(dsi, &msg);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_read);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_nop() - send DCS nop packet
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_NOP, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_nop);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_soft_reset() - perform a software reset of the display module
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SOFT_RESET, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_soft_reset);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_get_power_mode() - query the display module's current power
|
||||
* mode
|
||||
* @dsi: DSI peripheral device
|
||||
* @mode: return location for the current power mode
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_POWER_MODE, mode,
|
||||
sizeof(*mode));
|
||||
if (err <= 0) {
|
||||
if (err == 0)
|
||||
err = -ENODATA;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_get_power_mode);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_get_pixel_format() - gets the pixel format for the RGB image
|
||||
* data used by the interface
|
||||
* @dsi: DSI peripheral device
|
||||
* @format: return location for the pixel format
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_read(dsi, MIPI_DCS_GET_PIXEL_FORMAT, format,
|
||||
sizeof(*format));
|
||||
if (err <= 0) {
|
||||
if (err == 0)
|
||||
err = -ENODATA;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_get_pixel_format);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_enter_sleep_mode() - disable all unnecessary blocks inside the
|
||||
* display module except interface communication
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_ENTER_SLEEP_MODE, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_enter_sleep_mode);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_exit_sleep_mode() - enable all blocks inside the display
|
||||
* module
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_EXIT_SLEEP_MODE, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_exit_sleep_mode);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_display_off() - stop displaying the image data on the
|
||||
* display device
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_OFF, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_set_display_off);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_display_on() - start displaying the image data on the
|
||||
* display device
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure
|
||||
*/
|
||||
int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_ON, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_set_display_on);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_column_address() - define the column extent of the frame
|
||||
* memory accessed by the host processor
|
||||
* @dsi: DSI peripheral device
|
||||
* @start: first column of frame memory
|
||||
* @end: last column of frame memory
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
|
||||
u16 end)
|
||||
{
|
||||
u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_COLUMN_ADDRESS, payload,
|
||||
sizeof(payload));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_set_column_address);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_page_address() - define the page extent of the frame
|
||||
* memory accessed by the host processor
|
||||
* @dsi: DSI peripheral device
|
||||
* @start: first page of frame memory
|
||||
* @end: last page of frame memory
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
|
||||
u16 end)
|
||||
{
|
||||
u8 payload[4] = { start >> 8, start & 0xff, end >> 8, end & 0xff };
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PAGE_ADDRESS, payload,
|
||||
sizeof(payload));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_set_page_address);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_tear_off() - turn off the display module's Tearing Effect
|
||||
* output signal on the TE signal line
|
||||
* @dsi: DSI peripheral device
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure
|
||||
*/
|
||||
int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_OFF, NULL, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_off);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_tear_on() - turn on the display module's Tearing Effect
|
||||
* output signal on the TE signal line.
|
||||
* @dsi: DSI peripheral device
|
||||
* @mode: the Tearing Effect Output Line mode
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure
|
||||
*/
|
||||
int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
|
||||
enum mipi_dsi_dcs_tear_mode mode)
|
||||
{
|
||||
u8 value = mode;
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_TEAR_ON, &value,
|
||||
sizeof(value));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_on);
|
||||
|
||||
/**
|
||||
* mipi_dsi_dcs_set_pixel_format() - sets the pixel format for the RGB image
|
||||
* data used by the interface
|
||||
* @dsi: DSI peripheral device
|
||||
* @format: pixel format
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_PIXEL_FORMAT, &format,
|
||||
sizeof(format));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_dcs_set_pixel_format);
|
||||
|
||||
static int mipi_dsi_drv_probe(struct device *dev)
|
||||
{
|
||||
struct mipi_dsi_driver *drv = to_mipi_dsi_driver(dev->driver);
|
||||
|
@ -295,12 +887,18 @@ static void mipi_dsi_drv_shutdown(struct device *dev)
|
|||
}
|
||||
|
||||
/**
|
||||
* mipi_dsi_driver_register - register a driver for DSI devices
|
||||
* mipi_dsi_driver_register_full() - register a driver for DSI devices
|
||||
* @drv: DSI driver structure
|
||||
* @owner: owner module
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
int mipi_dsi_driver_register(struct mipi_dsi_driver *drv)
|
||||
int mipi_dsi_driver_register_full(struct mipi_dsi_driver *drv,
|
||||
struct module *owner)
|
||||
{
|
||||
drv->driver.bus = &mipi_dsi_bus_type;
|
||||
drv->driver.owner = owner;
|
||||
|
||||
if (drv->probe)
|
||||
drv->driver.probe = mipi_dsi_drv_probe;
|
||||
if (drv->remove)
|
||||
|
@ -310,11 +908,13 @@ int mipi_dsi_driver_register(struct mipi_dsi_driver *drv)
|
|||
|
||||
return driver_register(&drv->driver);
|
||||
}
|
||||
EXPORT_SYMBOL(mipi_dsi_driver_register);
|
||||
EXPORT_SYMBOL(mipi_dsi_driver_register_full);
|
||||
|
||||
/**
|
||||
* mipi_dsi_driver_unregister - unregister a driver for DSI devices
|
||||
* mipi_dsi_driver_unregister() - unregister a driver for DSI devices
|
||||
* @drv: DSI driver structure
|
||||
*
|
||||
* Return: 0 on success or a negative error code on failure.
|
||||
*/
|
||||
void mipi_dsi_driver_unregister(struct mipi_dsi_driver *drv)
|
||||
{
|
||||
|
|
|
@ -1236,7 +1236,7 @@ static bool exynos_dsi_is_short_dsi_type(u8 type)
|
|||
}
|
||||
|
||||
static ssize_t exynos_dsi_host_transfer(struct mipi_dsi_host *host,
|
||||
struct mipi_dsi_msg *msg)
|
||||
const struct mipi_dsi_msg *msg)
|
||||
{
|
||||
struct exynos_dsi *dsi = host_to_dsi(host);
|
||||
struct exynos_dsi_transfer xfer;
|
||||
|
|
|
@ -27,4 +27,17 @@ config DRM_PANEL_S6E8AA0
|
|||
select DRM_MIPI_DSI
|
||||
select VIDEOMODE_HELPERS
|
||||
|
||||
config DRM_PANEL_SHARP_LQ101R1SX01
|
||||
tristate "Sharp LQ101R1SX01 panel"
|
||||
depends on OF
|
||||
depends on DRM_MIPI_DSI
|
||||
help
|
||||
Say Y here if you want to enable support for Sharp LQ101R1SX01
|
||||
TFT-LCD modules. The panel has a 2560x1600 resolution and uses
|
||||
24 bit RGB per pixel. It provides a dual MIPI DSI interface to
|
||||
the host and has a built-in LED backlight.
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called panel-sharp-lq101r1sx01.
|
||||
|
||||
endmenu
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
obj-$(CONFIG_DRM_PANEL_SIMPLE) += panel-simple.o
|
||||
obj-$(CONFIG_DRM_PANEL_LD9040) += panel-ld9040.o
|
||||
obj-$(CONFIG_DRM_PANEL_S6E8AA0) += panel-s6e8aa0.o
|
||||
obj-$(CONFIG_DRM_PANEL_SHARP_LQ101R1SX01) += panel-sharp-lq101r1sx01.o
|
||||
|
|
|
@ -145,7 +145,7 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len)
|
|||
if (ctx->error < 0 || len == 0)
|
||||
return;
|
||||
|
||||
dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", len, data);
|
||||
dev_dbg(ctx->dev, "writing dcs seq: %*ph\n", (int)len, data);
|
||||
ret = ld9040_spi_write_word(ctx, *data);
|
||||
|
||||
while (!ret && --len) {
|
||||
|
@ -154,8 +154,8 @@ static void ld9040_dcs_write(struct ld9040 *ctx, const u8 *data, size_t len)
|
|||
}
|
||||
|
||||
if (ret) {
|
||||
dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret, len,
|
||||
data);
|
||||
dev_err(ctx->dev, "error %d writing dcs seq: %*ph\n", ret,
|
||||
(int)len, data);
|
||||
ctx->error = ret;
|
||||
}
|
||||
|
||||
|
@ -336,17 +336,12 @@ static int ld9040_probe(struct spi_device *spi)
|
|||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset");
|
||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(ctx->reset_gpio)) {
|
||||
dev_err(dev, "cannot get reset-gpios %ld\n",
|
||||
PTR_ERR(ctx->reset_gpio));
|
||||
return PTR_ERR(ctx->reset_gpio);
|
||||
}
|
||||
ret = gpiod_direction_output(ctx->reset_gpio, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot configure reset-gpios %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi->bits_per_word = 9;
|
||||
ret = spi_setup(spi);
|
||||
|
|
|
@ -141,10 +141,10 @@ static void s6e8aa0_dcs_write(struct s6e8aa0 *ctx, const void *data, size_t len)
|
|||
if (ctx->error < 0)
|
||||
return;
|
||||
|
||||
ret = mipi_dsi_dcs_write(dsi, data, len);
|
||||
ret = mipi_dsi_dcs_write_buffer(dsi, data, len);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret, len,
|
||||
data);
|
||||
dev_err(ctx->dev, "error %zd writing dcs seq: %*ph\n", ret,
|
||||
(int)len, data);
|
||||
ctx->error = ret;
|
||||
}
|
||||
}
|
||||
|
@ -800,27 +800,15 @@ static void s6e8aa0_panel_init(struct s6e8aa0 *ctx)
|
|||
}
|
||||
|
||||
static void s6e8aa0_set_maximum_return_packet_size(struct s6e8aa0 *ctx,
|
||||
int size)
|
||||
u16 size)
|
||||
{
|
||||
struct mipi_dsi_device *dsi = to_mipi_dsi_device(ctx->dev);
|
||||
const struct mipi_dsi_host_ops *ops = dsi->host->ops;
|
||||
u8 buf[] = {size, 0};
|
||||
struct mipi_dsi_msg msg = {
|
||||
.channel = dsi->channel,
|
||||
.type = MIPI_DSI_SET_MAXIMUM_RETURN_PACKET_SIZE,
|
||||
.tx_len = sizeof(buf),
|
||||
.tx_buf = buf
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (ctx->error < 0)
|
||||
return;
|
||||
|
||||
if (!ops || !ops->transfer)
|
||||
ret = -EIO;
|
||||
else
|
||||
ret = ops->transfer(dsi->host, &msg);
|
||||
|
||||
ret = mipi_dsi_set_maximum_return_packet_size(dsi, size);
|
||||
if (ret < 0) {
|
||||
dev_err(ctx->dev,
|
||||
"error %d setting maximum return packet size to %d\n",
|
||||
|
@ -1019,17 +1007,12 @@ static int s6e8aa0_probe(struct mipi_dsi_device *dsi)
|
|||
return ret;
|
||||
}
|
||||
|
||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset");
|
||||
ctx->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
|
||||
if (IS_ERR(ctx->reset_gpio)) {
|
||||
dev_err(dev, "cannot get reset-gpios %ld\n",
|
||||
PTR_ERR(ctx->reset_gpio));
|
||||
return PTR_ERR(ctx->reset_gpio);
|
||||
}
|
||||
ret = gpiod_direction_output(ctx->reset_gpio, 1);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "cannot configure reset-gpios %d\n", ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
ctx->brightness = GAMMA_LEVEL_NUM - 1;
|
||||
|
||||
|
@ -1069,7 +1052,6 @@ static struct mipi_dsi_driver s6e8aa0_driver = {
|
|||
.remove = s6e8aa0_remove,
|
||||
.driver = {
|
||||
.name = "panel_s6e8aa0",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = s6e8aa0_of_match,
|
||||
},
|
||||
};
|
||||
|
|
|
@ -0,0 +1,464 @@
|
|||
/*
|
||||
* Copyright (C) 2014 NVIDIA Corporation
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
|
||||
#include <linux/backlight.h>
|
||||
#include <linux/gpio/consumer.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/regulator/consumer.h>
|
||||
|
||||
#include <drm/drmP.h>
|
||||
#include <drm/drm_crtc.h>
|
||||
#include <drm/drm_mipi_dsi.h>
|
||||
#include <drm/drm_panel.h>
|
||||
|
||||
#include <video/mipi_display.h>
|
||||
|
||||
#include <linux/host1x.h>
|
||||
|
||||
struct sharp_panel {
|
||||
struct drm_panel base;
|
||||
/* the datasheet refers to them as DSI-LINK1 and DSI-LINK2 */
|
||||
struct mipi_dsi_device *link1;
|
||||
struct mipi_dsi_device *link2;
|
||||
|
||||
struct backlight_device *backlight;
|
||||
struct regulator *supply;
|
||||
|
||||
bool prepared;
|
||||
bool enabled;
|
||||
|
||||
const struct drm_display_mode *mode;
|
||||
};
|
||||
|
||||
static inline struct sharp_panel *to_sharp_panel(struct drm_panel *panel)
|
||||
{
|
||||
return container_of(panel, struct sharp_panel, base);
|
||||
}
|
||||
|
||||
static int sharp_panel_write(struct sharp_panel *sharp, u16 offset, u8 value)
|
||||
{
|
||||
u8 payload[3] = { offset >> 8, offset & 0xff, value };
|
||||
struct mipi_dsi_device *dsi = sharp->link1;
|
||||
ssize_t err;
|
||||
|
||||
err = mipi_dsi_generic_write(dsi, payload, sizeof(payload));
|
||||
if (err < 0) {
|
||||
dev_err(&dsi->dev, "failed to write %02x to %04x: %zd\n",
|
||||
value, offset, err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mipi_dsi_dcs_nop(dsi);
|
||||
if (err < 0) {
|
||||
dev_err(&dsi->dev, "failed to send DCS nop: %zd\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
usleep_range(10, 20);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __maybe_unused int sharp_panel_read(struct sharp_panel *sharp,
|
||||
u16 offset, u8 *value)
|
||||
{
|
||||
ssize_t err;
|
||||
|
||||
cpu_to_be16s(&offset);
|
||||
|
||||
err = mipi_dsi_generic_read(sharp->link1, &offset, sizeof(offset),
|
||||
value, sizeof(*value));
|
||||
if (err < 0)
|
||||
dev_err(&sharp->link1->dev, "failed to read from %04x: %zd\n",
|
||||
offset, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sharp_panel_disable(struct drm_panel *panel)
|
||||
{
|
||||
struct sharp_panel *sharp = to_sharp_panel(panel);
|
||||
|
||||
if (!sharp->enabled)
|
||||
return 0;
|
||||
|
||||
if (sharp->backlight) {
|
||||
sharp->backlight->props.power = FB_BLANK_POWERDOWN;
|
||||
backlight_update_status(sharp->backlight);
|
||||
}
|
||||
|
||||
sharp->enabled = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sharp_panel_unprepare(struct drm_panel *panel)
|
||||
{
|
||||
struct sharp_panel *sharp = to_sharp_panel(panel);
|
||||
int err;
|
||||
|
||||
if (!sharp->prepared)
|
||||
return 0;
|
||||
|
||||
err = mipi_dsi_dcs_set_display_off(sharp->link1);
|
||||
if (err < 0)
|
||||
dev_err(panel->dev, "failed to set display off: %d\n", err);
|
||||
|
||||
err = mipi_dsi_dcs_enter_sleep_mode(sharp->link1);
|
||||
if (err < 0)
|
||||
dev_err(panel->dev, "failed to enter sleep mode: %d\n", err);
|
||||
|
||||
msleep(120);
|
||||
|
||||
regulator_disable(sharp->supply);
|
||||
|
||||
sharp->prepared = false;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sharp_setup_symmetrical_split(struct mipi_dsi_device *left,
|
||||
struct mipi_dsi_device *right,
|
||||
const struct drm_display_mode *mode)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = mipi_dsi_dcs_set_column_address(left, 0, mode->hdisplay / 2 - 1);
|
||||
if (err < 0) {
|
||||
dev_err(&left->dev, "failed to set column address: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mipi_dsi_dcs_set_page_address(left, 0, mode->vdisplay - 1);
|
||||
if (err < 0) {
|
||||
dev_err(&left->dev, "failed to set page address: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mipi_dsi_dcs_set_column_address(right, mode->hdisplay / 2,
|
||||
mode->hdisplay - 1);
|
||||
if (err < 0) {
|
||||
dev_err(&right->dev, "failed to set column address: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = mipi_dsi_dcs_set_page_address(right, 0, mode->vdisplay - 1);
|
||||
if (err < 0) {
|
||||
dev_err(&right->dev, "failed to set page address: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sharp_panel_prepare(struct drm_panel *panel)
|
||||
{
|
||||
struct sharp_panel *sharp = to_sharp_panel(panel);
|
||||
u8 format = MIPI_DCS_PIXEL_FMT_24BIT;
|
||||
int err;
|
||||
|
||||
if (sharp->prepared)
|
||||
return 0;
|
||||
|
||||
err = regulator_enable(sharp->supply);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
usleep_range(10000, 20000);
|
||||
|
||||
err = mipi_dsi_dcs_soft_reset(sharp->link1);
|
||||
if (err < 0) {
|
||||
dev_err(panel->dev, "soft reset failed: %d\n", err);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
msleep(120);
|
||||
|
||||
err = mipi_dsi_dcs_exit_sleep_mode(sharp->link1);
|
||||
if (err < 0) {
|
||||
dev_err(panel->dev, "failed to exit sleep mode: %d\n", err);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
/*
|
||||
* The MIPI DCS specification mandates this delay only between the
|
||||
* exit_sleep_mode and enter_sleep_mode commands, so it isn't strictly
|
||||
* necessary here.
|
||||
*/
|
||||
/*
|
||||
msleep(120);
|
||||
*/
|
||||
|
||||
/* set left-right mode */
|
||||
err = sharp_panel_write(sharp, 0x1000, 0x2a);
|
||||
if (err < 0) {
|
||||
dev_err(panel->dev, "failed to set left-right mode: %d\n", err);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
/* enable command mode */
|
||||
err = sharp_panel_write(sharp, 0x1001, 0x01);
|
||||
if (err < 0) {
|
||||
dev_err(panel->dev, "failed to enable command mode: %d\n", err);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
err = mipi_dsi_dcs_set_pixel_format(sharp->link1, format);
|
||||
if (err < 0) {
|
||||
dev_err(panel->dev, "failed to set pixel format: %d\n", err);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: The device supports both left-right and even-odd split
|
||||
* configurations, but this driver currently supports only the left-
|
||||
* right split. To support a different mode a mechanism needs to be
|
||||
* put in place to communicate the configuration back to the DSI host
|
||||
* controller.
|
||||
*/
|
||||
err = sharp_setup_symmetrical_split(sharp->link1, sharp->link2,
|
||||
sharp->mode);
|
||||
if (err < 0) {
|
||||
dev_err(panel->dev, "failed to set up symmetrical split: %d\n",
|
||||
err);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
err = mipi_dsi_dcs_set_display_on(sharp->link1);
|
||||
if (err < 0) {
|
||||
dev_err(panel->dev, "failed to set display on: %d\n", err);
|
||||
goto poweroff;
|
||||
}
|
||||
|
||||
sharp->prepared = true;
|
||||
|
||||
return 0;
|
||||
|
||||
poweroff:
|
||||
regulator_disable(sharp->supply);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int sharp_panel_enable(struct drm_panel *panel)
|
||||
{
|
||||
struct sharp_panel *sharp = to_sharp_panel(panel);
|
||||
|
||||
if (sharp->enabled)
|
||||
return 0;
|
||||
|
||||
if (sharp->backlight) {
|
||||
sharp->backlight->props.power = FB_BLANK_UNBLANK;
|
||||
backlight_update_status(sharp->backlight);
|
||||
}
|
||||
|
||||
sharp->enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct drm_display_mode default_mode = {
|
||||
.clock = 278000,
|
||||
.hdisplay = 2560,
|
||||
.hsync_start = 2560 + 128,
|
||||
.hsync_end = 2560 + 128 + 64,
|
||||
.htotal = 2560 + 128 + 64 + 64,
|
||||
.vdisplay = 1600,
|
||||
.vsync_start = 1600 + 4,
|
||||
.vsync_end = 1600 + 4 + 8,
|
||||
.vtotal = 1600 + 4 + 8 + 32,
|
||||
.vrefresh = 60,
|
||||
};
|
||||
|
||||
static int sharp_panel_get_modes(struct drm_panel *panel)
|
||||
{
|
||||
struct drm_display_mode *mode;
|
||||
|
||||
mode = drm_mode_duplicate(panel->drm, &default_mode);
|
||||
if (!mode) {
|
||||
dev_err(panel->drm->dev, "failed to add mode %ux%ux@%u\n",
|
||||
default_mode.hdisplay, default_mode.vdisplay,
|
||||
default_mode.vrefresh);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
drm_mode_set_name(mode);
|
||||
|
||||
drm_mode_probed_add(panel->connector, mode);
|
||||
|
||||
panel->connector->display_info.width_mm = 217;
|
||||
panel->connector->display_info.height_mm = 136;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const struct drm_panel_funcs sharp_panel_funcs = {
|
||||
.disable = sharp_panel_disable,
|
||||
.unprepare = sharp_panel_unprepare,
|
||||
.prepare = sharp_panel_prepare,
|
||||
.enable = sharp_panel_enable,
|
||||
.get_modes = sharp_panel_get_modes,
|
||||
};
|
||||
|
||||
static const struct of_device_id sharp_of_match[] = {
|
||||
{ .compatible = "sharp,lq101r1sx01", },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, sharp_of_match);
|
||||
|
||||
static int sharp_panel_add(struct sharp_panel *sharp)
|
||||
{
|
||||
struct device_node *np;
|
||||
int err;
|
||||
|
||||
sharp->mode = &default_mode;
|
||||
|
||||
sharp->supply = devm_regulator_get(&sharp->link1->dev, "power");
|
||||
if (IS_ERR(sharp->supply))
|
||||
return PTR_ERR(sharp->supply);
|
||||
|
||||
np = of_parse_phandle(sharp->link1->dev.of_node, "backlight", 0);
|
||||
if (np) {
|
||||
sharp->backlight = of_find_backlight_by_node(np);
|
||||
of_node_put(np);
|
||||
|
||||
if (!sharp->backlight)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
drm_panel_init(&sharp->base);
|
||||
sharp->base.funcs = &sharp_panel_funcs;
|
||||
sharp->base.dev = &sharp->link1->dev;
|
||||
|
||||
err = drm_panel_add(&sharp->base);
|
||||
if (err < 0)
|
||||
goto put_backlight;
|
||||
|
||||
return 0;
|
||||
|
||||
put_backlight:
|
||||
if (sharp->backlight)
|
||||
put_device(&sharp->backlight->dev);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void sharp_panel_del(struct sharp_panel *sharp)
|
||||
{
|
||||
if (sharp->base.dev)
|
||||
drm_panel_remove(&sharp->base);
|
||||
|
||||
if (sharp->backlight)
|
||||
put_device(&sharp->backlight->dev);
|
||||
|
||||
if (sharp->link2)
|
||||
put_device(&sharp->link2->dev);
|
||||
}
|
||||
|
||||
static int sharp_panel_probe(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct mipi_dsi_device *secondary = NULL;
|
||||
struct sharp_panel *sharp;
|
||||
struct device_node *np;
|
||||
int err;
|
||||
|
||||
dsi->lanes = 4;
|
||||
dsi->format = MIPI_DSI_FMT_RGB888;
|
||||
dsi->mode_flags = MIPI_DSI_MODE_LPM;
|
||||
|
||||
/* Find DSI-LINK1 */
|
||||
np = of_parse_phandle(dsi->dev.of_node, "link2", 0);
|
||||
if (np) {
|
||||
secondary = of_find_mipi_dsi_device_by_node(np);
|
||||
of_node_put(np);
|
||||
|
||||
if (!secondary)
|
||||
return -EPROBE_DEFER;
|
||||
}
|
||||
|
||||
/* register a panel for only the DSI-LINK1 interface */
|
||||
if (secondary) {
|
||||
sharp = devm_kzalloc(&dsi->dev, sizeof(*sharp), GFP_KERNEL);
|
||||
if (!sharp) {
|
||||
put_device(&secondary->dev);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
mipi_dsi_set_drvdata(dsi, sharp);
|
||||
|
||||
sharp->link2 = secondary;
|
||||
sharp->link1 = dsi;
|
||||
|
||||
err = sharp_panel_add(sharp);
|
||||
if (err < 0) {
|
||||
put_device(&secondary->dev);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
err = mipi_dsi_attach(dsi);
|
||||
if (err < 0) {
|
||||
if (secondary)
|
||||
sharp_panel_del(sharp);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int sharp_panel_remove(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi);
|
||||
int err;
|
||||
|
||||
/* only detach from host for the DSI-LINK2 interface */
|
||||
if (!sharp) {
|
||||
mipi_dsi_detach(dsi);
|
||||
return 0;
|
||||
}
|
||||
|
||||
err = sharp_panel_disable(&sharp->base);
|
||||
if (err < 0)
|
||||
dev_err(&dsi->dev, "failed to disable panel: %d\n", err);
|
||||
|
||||
err = mipi_dsi_detach(dsi);
|
||||
if (err < 0)
|
||||
dev_err(&dsi->dev, "failed to detach from DSI host: %d\n", err);
|
||||
|
||||
drm_panel_detach(&sharp->base);
|
||||
sharp_panel_del(sharp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void sharp_panel_shutdown(struct mipi_dsi_device *dsi)
|
||||
{
|
||||
struct sharp_panel *sharp = mipi_dsi_get_drvdata(dsi);
|
||||
|
||||
/* nothing to do for DSI-LINK2 */
|
||||
if (!sharp)
|
||||
return;
|
||||
|
||||
sharp_panel_disable(&sharp->base);
|
||||
}
|
||||
|
||||
static struct mipi_dsi_driver sharp_panel_driver = {
|
||||
.driver = {
|
||||
.name = "panel-sharp-lq101r1sx01",
|
||||
.of_match_table = sharp_of_match,
|
||||
},
|
||||
.probe = sharp_panel_probe,
|
||||
.remove = sharp_panel_remove,
|
||||
.shutdown = sharp_panel_shutdown,
|
||||
};
|
||||
module_mipi_dsi_driver(sharp_panel_driver);
|
||||
|
||||
MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
|
||||
MODULE_DESCRIPTION("Sharp LQ101R1SX01 panel driver");
|
||||
MODULE_LICENSE("GPL v2");
|
|
@ -247,21 +247,14 @@ static int panel_simple_probe(struct device *dev, const struct panel_desc *desc)
|
|||
if (IS_ERR(panel->supply))
|
||||
return PTR_ERR(panel->supply);
|
||||
|
||||
panel->enable_gpio = devm_gpiod_get_optional(dev, "enable");
|
||||
panel->enable_gpio = devm_gpiod_get_optional(dev, "enable",
|
||||
GPIOD_OUT_LOW);
|
||||
if (IS_ERR(panel->enable_gpio)) {
|
||||
err = PTR_ERR(panel->enable_gpio);
|
||||
dev_err(dev, "failed to request GPIO: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
|
||||
if (panel->enable_gpio) {
|
||||
err = gpiod_direction_output(panel->enable_gpio, 0);
|
||||
if (err < 0) {
|
||||
dev_err(dev, "failed to setup GPIO: %d\n", err);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
backlight = of_parse_phandle(dev->of_node, "backlight", 0);
|
||||
if (backlight) {
|
||||
panel->backlight = of_find_backlight_by_node(backlight);
|
||||
|
@ -376,6 +369,29 @@ static const struct panel_desc auo_b101xtn01 = {
|
|||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode auo_b116xw03_mode = {
|
||||
.clock = 70589,
|
||||
.hdisplay = 1366,
|
||||
.hsync_start = 1366 + 40,
|
||||
.hsync_end = 1366 + 40 + 40,
|
||||
.htotal = 1366 + 40 + 40 + 32,
|
||||
.vdisplay = 768,
|
||||
.vsync_start = 768 + 10,
|
||||
.vsync_end = 768 + 10 + 12,
|
||||
.vtotal = 768 + 10 + 12 + 6,
|
||||
.vrefresh = 60,
|
||||
};
|
||||
|
||||
static const struct panel_desc auo_b116xw03 = {
|
||||
.modes = &auo_b116xw03_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 6,
|
||||
.size = {
|
||||
.width = 256,
|
||||
.height = 144,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode auo_b133xtn01_mode = {
|
||||
.clock = 69500,
|
||||
.hdisplay = 1366,
|
||||
|
@ -415,6 +431,7 @@ static const struct drm_display_mode auo_b133htn01_mode = {
|
|||
static const struct panel_desc auo_b133htn01 = {
|
||||
.modes = &auo_b133htn01_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 6,
|
||||
.size = {
|
||||
.width = 293,
|
||||
.height = 165,
|
||||
|
@ -536,22 +553,92 @@ static const struct drm_display_mode foxlink_fl500wvr00_a0t_mode = {
|
|||
static const struct panel_desc foxlink_fl500wvr00_a0t = {
|
||||
.modes = &foxlink_fl500wvr00_a0t_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 108,
|
||||
.height = 65,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode innolux_n116bge_mode = {
|
||||
static const struct drm_display_mode hannstar_hsd070pww1_mode = {
|
||||
.clock = 71100,
|
||||
.hdisplay = 1280,
|
||||
.hsync_start = 1280 + 1,
|
||||
.hsync_end = 1280 + 1 + 158,
|
||||
.htotal = 1280 + 1 + 158 + 1,
|
||||
.vdisplay = 800,
|
||||
.vsync_start = 800 + 1,
|
||||
.vsync_end = 800 + 1 + 21,
|
||||
.vtotal = 800 + 1 + 21 + 1,
|
||||
.vrefresh = 60,
|
||||
};
|
||||
|
||||
static const struct panel_desc hannstar_hsd070pww1 = {
|
||||
.modes = &hannstar_hsd070pww1_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 6,
|
||||
.size = {
|
||||
.width = 151,
|
||||
.height = 94,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode hitachi_tx23d38vm0caa_mode = {
|
||||
.clock = 33333,
|
||||
.hdisplay = 800,
|
||||
.hsync_start = 800 + 85,
|
||||
.hsync_end = 800 + 85 + 86,
|
||||
.htotal = 800 + 85 + 86 + 85,
|
||||
.vdisplay = 480,
|
||||
.vsync_start = 480 + 16,
|
||||
.vsync_end = 480 + 16 + 13,
|
||||
.vtotal = 480 + 16 + 13 + 16,
|
||||
.vrefresh = 60,
|
||||
};
|
||||
|
||||
static const struct panel_desc hitachi_tx23d38vm0caa = {
|
||||
.modes = &hitachi_tx23d38vm0caa_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 6,
|
||||
.size = {
|
||||
.width = 195,
|
||||
.height = 117,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode innolux_g121i1_l01_mode = {
|
||||
.clock = 71000,
|
||||
.hdisplay = 1280,
|
||||
.hsync_start = 1280 + 64,
|
||||
.hsync_end = 1280 + 64 + 32,
|
||||
.htotal = 1280 + 64 + 32 + 64,
|
||||
.vdisplay = 800,
|
||||
.vsync_start = 800 + 9,
|
||||
.vsync_end = 800 + 9 + 6,
|
||||
.vtotal = 800 + 9 + 6 + 9,
|
||||
.vrefresh = 60,
|
||||
};
|
||||
|
||||
static const struct panel_desc innolux_g121i1_l01 = {
|
||||
.modes = &innolux_g121i1_l01_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 6,
|
||||
.size = {
|
||||
.width = 261,
|
||||
.height = 163,
|
||||
},
|
||||
};
|
||||
|
||||
static const struct drm_display_mode innolux_n116bge_mode = {
|
||||
.clock = 76420,
|
||||
.hdisplay = 1366,
|
||||
.hsync_start = 1366 + 64,
|
||||
.hsync_end = 1366 + 64 + 6,
|
||||
.htotal = 1366 + 64 + 6 + 64,
|
||||
.hsync_start = 1366 + 136,
|
||||
.hsync_end = 1366 + 136 + 30,
|
||||
.htotal = 1366 + 136 + 30 + 60,
|
||||
.vdisplay = 768,
|
||||
.vsync_start = 768 + 8,
|
||||
.vsync_end = 768 + 8 + 4,
|
||||
.vtotal = 768 + 8 + 4 + 8,
|
||||
.vsync_end = 768 + 8 + 12,
|
||||
.vtotal = 768 + 8 + 12 + 12,
|
||||
.vrefresh = 60,
|
||||
.flags = DRM_MODE_FLAG_NHSYNC | DRM_MODE_FLAG_NVSYNC,
|
||||
};
|
||||
|
@ -642,6 +729,9 @@ static const struct of_device_id platform_of_match[] = {
|
|||
}, {
|
||||
.compatible = "auo,b101xtn01",
|
||||
.data = &auo_b101xtn01,
|
||||
}, {
|
||||
.compatible = "auo,b116xw03",
|
||||
.data = &auo_b116xw03,
|
||||
}, {
|
||||
.compatible = "auo,b133htn01",
|
||||
.data = &auo_b133htn01,
|
||||
|
@ -666,6 +756,15 @@ static const struct of_device_id platform_of_match[] = {
|
|||
}, {
|
||||
.compatible = "foxlink,fl500wvr00-a0t",
|
||||
.data = &foxlink_fl500wvr00_a0t,
|
||||
}, {
|
||||
.compatible = "hannstar,hsd070pww1",
|
||||
.data = &hannstar_hsd070pww1,
|
||||
}, {
|
||||
.compatible = "hit,tx23d38vm0caa",
|
||||
.data = &hitachi_tx23d38vm0caa
|
||||
}, {
|
||||
.compatible ="innolux,g121i1-l01",
|
||||
.data = &innolux_g121i1_l01
|
||||
}, {
|
||||
.compatible = "innolux,n116bge",
|
||||
.data = &innolux_n116bge,
|
||||
|
@ -741,6 +840,7 @@ static const struct panel_desc_dsi lg_ld070wx3_sl01 = {
|
|||
.desc = {
|
||||
.modes = &lg_ld070wx3_sl01_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 94,
|
||||
.height = 151,
|
||||
|
@ -768,6 +868,7 @@ static const struct panel_desc_dsi lg_lh500wx1_sd03 = {
|
|||
.desc = {
|
||||
.modes = &lg_lh500wx1_sd03_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 62,
|
||||
.height = 110,
|
||||
|
@ -795,6 +896,7 @@ static const struct panel_desc_dsi panasonic_vvx10f004b00 = {
|
|||
.desc = {
|
||||
.modes = &panasonic_vvx10f004b00_mode,
|
||||
.num_modes = 1,
|
||||
.bpc = 8,
|
||||
.size = {
|
||||
.width = 217,
|
||||
.height = 136,
|
||||
|
@ -864,7 +966,6 @@ static void panel_simple_dsi_shutdown(struct mipi_dsi_device *dsi)
|
|||
static struct mipi_dsi_driver panel_simple_dsi_driver = {
|
||||
.driver = {
|
||||
.name = "panel-simple-dsi",
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = dsi_of_match,
|
||||
},
|
||||
.probe = panel_simple_dsi_probe,
|
||||
|
|
|
@ -26,6 +26,7 @@ struct mipi_dsi_device;
|
|||
* struct mipi_dsi_msg - read/write DSI buffer
|
||||
* @channel: virtual channel id
|
||||
* @type: payload data type
|
||||
* @flags: flags controlling this message transmission
|
||||
* @tx_len: length of @tx_buf
|
||||
* @tx_buf: data to be written
|
||||
* @rx_len: length of @rx_buf
|
||||
|
@ -43,12 +44,44 @@ struct mipi_dsi_msg {
|
|||
void *rx_buf;
|
||||
};
|
||||
|
||||
bool mipi_dsi_packet_format_is_short(u8 type);
|
||||
bool mipi_dsi_packet_format_is_long(u8 type);
|
||||
|
||||
/**
|
||||
* struct mipi_dsi_packet - represents a MIPI DSI packet in protocol format
|
||||
* @size: size (in bytes) of the packet
|
||||
* @header: the four bytes that make up the header (Data ID, Word Count or
|
||||
* Packet Data, and ECC)
|
||||
* @payload_length: number of bytes in the payload
|
||||
* @payload: a pointer to a buffer containing the payload, if any
|
||||
*/
|
||||
struct mipi_dsi_packet {
|
||||
size_t size;
|
||||
u8 header[4];
|
||||
size_t payload_length;
|
||||
const u8 *payload;
|
||||
};
|
||||
|
||||
int mipi_dsi_create_packet(struct mipi_dsi_packet *packet,
|
||||
const struct mipi_dsi_msg *msg);
|
||||
|
||||
/**
|
||||
* struct mipi_dsi_host_ops - DSI bus operations
|
||||
* @attach: attach DSI device to DSI host
|
||||
* @detach: detach DSI device from DSI host
|
||||
* @transfer: send and/or receive DSI packet, return number of received bytes,
|
||||
* or error
|
||||
* @transfer: transmit a DSI packet
|
||||
*
|
||||
* DSI packets transmitted by .transfer() are passed in as mipi_dsi_msg
|
||||
* structures. This structure contains information about the type of packet
|
||||
* being transmitted as well as the transmit and receive buffers. When an
|
||||
* error is encountered during transmission, this function will return a
|
||||
* negative error code. On success it shall return the number of bytes
|
||||
* transmitted for write packets or the number of bytes received for read
|
||||
* packets.
|
||||
*
|
||||
* Note that typically DSI packet transmission is atomic, so the .transfer()
|
||||
* function will seldomly return anything other than the number of bytes
|
||||
* contained in the transmit buffer on success.
|
||||
*/
|
||||
struct mipi_dsi_host_ops {
|
||||
int (*attach)(struct mipi_dsi_host *host,
|
||||
|
@ -56,7 +89,7 @@ struct mipi_dsi_host_ops {
|
|||
int (*detach)(struct mipi_dsi_host *host,
|
||||
struct mipi_dsi_device *dsi);
|
||||
ssize_t (*transfer)(struct mipi_dsi_host *host,
|
||||
struct mipi_dsi_msg *msg);
|
||||
const struct mipi_dsi_msg *msg);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -130,12 +163,57 @@ static inline struct mipi_dsi_device *to_mipi_dsi_device(struct device *dev)
|
|||
return container_of(dev, struct mipi_dsi_device, dev);
|
||||
}
|
||||
|
||||
struct mipi_dsi_device *of_find_mipi_dsi_device_by_node(struct device_node *np);
|
||||
int mipi_dsi_attach(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_detach(struct mipi_dsi_device *dsi);
|
||||
ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, const void *data,
|
||||
size_t len);
|
||||
int mipi_dsi_set_maximum_return_packet_size(struct mipi_dsi_device *dsi,
|
||||
u16 value);
|
||||
|
||||
ssize_t mipi_dsi_generic_write(struct mipi_dsi_device *dsi, const void *payload,
|
||||
size_t size);
|
||||
ssize_t mipi_dsi_generic_read(struct mipi_dsi_device *dsi, const void *params,
|
||||
size_t num_params, void *data, size_t size);
|
||||
|
||||
/**
|
||||
* enum mipi_dsi_dcs_tear_mode - Tearing Effect Output Line mode
|
||||
* @MIPI_DSI_DCS_TEAR_MODE_VBLANK: the TE output line consists of V-Blanking
|
||||
* information only
|
||||
* @MIPI_DSI_DCS_TEAR_MODE_VHBLANK : the TE output line consists of both
|
||||
* V-Blanking and H-Blanking information
|
||||
*/
|
||||
enum mipi_dsi_dcs_tear_mode {
|
||||
MIPI_DSI_DCS_TEAR_MODE_VBLANK,
|
||||
MIPI_DSI_DCS_TEAR_MODE_VHBLANK,
|
||||
};
|
||||
|
||||
#define MIPI_DSI_DCS_POWER_MODE_DISPLAY (1 << 2)
|
||||
#define MIPI_DSI_DCS_POWER_MODE_NORMAL (1 << 3)
|
||||
#define MIPI_DSI_DCS_POWER_MODE_SLEEP (1 << 4)
|
||||
#define MIPI_DSI_DCS_POWER_MODE_PARTIAL (1 << 5)
|
||||
#define MIPI_DSI_DCS_POWER_MODE_IDLE (1 << 6)
|
||||
|
||||
ssize_t mipi_dsi_dcs_write_buffer(struct mipi_dsi_device *dsi,
|
||||
const void *data, size_t len);
|
||||
ssize_t mipi_dsi_dcs_write(struct mipi_dsi_device *dsi, u8 cmd,
|
||||
const void *data, size_t len);
|
||||
ssize_t mipi_dsi_dcs_read(struct mipi_dsi_device *dsi, u8 cmd, void *data,
|
||||
size_t len);
|
||||
int mipi_dsi_dcs_nop(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_soft_reset(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_get_power_mode(struct mipi_dsi_device *dsi, u8 *mode);
|
||||
int mipi_dsi_dcs_get_pixel_format(struct mipi_dsi_device *dsi, u8 *format);
|
||||
int mipi_dsi_dcs_enter_sleep_mode(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_exit_sleep_mode(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_set_display_off(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_set_display_on(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_set_column_address(struct mipi_dsi_device *dsi, u16 start,
|
||||
u16 end);
|
||||
int mipi_dsi_dcs_set_page_address(struct mipi_dsi_device *dsi, u16 start,
|
||||
u16 end);
|
||||
int mipi_dsi_dcs_set_tear_off(struct mipi_dsi_device *dsi);
|
||||
int mipi_dsi_dcs_set_tear_on(struct mipi_dsi_device *dsi,
|
||||
enum mipi_dsi_dcs_tear_mode mode);
|
||||
int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format);
|
||||
|
||||
/**
|
||||
* struct mipi_dsi_driver - DSI driver
|
||||
|
@ -167,9 +245,13 @@ static inline void mipi_dsi_set_drvdata(struct mipi_dsi_device *dsi, void *data)
|
|||
dev_set_drvdata(&dsi->dev, data);
|
||||
}
|
||||
|
||||
int mipi_dsi_driver_register(struct mipi_dsi_driver *driver);
|
||||
int mipi_dsi_driver_register_full(struct mipi_dsi_driver *driver,
|
||||
struct module *owner);
|
||||
void mipi_dsi_driver_unregister(struct mipi_dsi_driver *driver);
|
||||
|
||||
#define mipi_dsi_driver_register(driver) \
|
||||
mipi_dsi_driver_register_full(driver, THIS_MODULE)
|
||||
|
||||
#define module_mipi_dsi_driver(__mipi_dsi_driver) \
|
||||
module_driver(__mipi_dsi_driver, mipi_dsi_driver_register, \
|
||||
mipi_dsi_driver_unregister)
|
||||
|
|
Loading…
Reference in New Issue