Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 54f20609 authored by qctecmdr Service's avatar qctecmdr Service Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm:mdss: Add SPI client driver for SPI display"

parents b4a2f6c0 a0fe73c5
Loading
Loading
Loading
Loading
+26 −0
Original line number Diff line number Diff line
Qualcomm Technologies, Inc. mdss-spi-client

mdss-spi-client is for spi display send the FB data to spi master.

Required properties:
- compatible : should be "qcom,mdss-spi-client"
- spi-max-frequency : Maximum SPI clocking speed of device in Hz

Optional properties:
- label: A string used to describe the controller used.
- spi-cpol : Empty property indicating device requires inverse
  clock polarity (CPOL) mode
- spi-cpha :  Empty property indicating device requires shifted
  clock phase (CPHA) mode
- spi-cs-high :  Empty property indicating device requires
  chip select active high

Example:
spi@78b9000 { /* BLSP1 QUP5 */
               qcom,mdss_spi_client{
               reg = <0>;
               compatible = "qcom,mdss-spi-client";
               label = "MDSS SPI QUP5 CLIENT";
               spi-max-frequency = <50000000>;
               };
};
+218 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/spi/spi.h>

#include "mdss_spi_client.h"

#define MAX_READ_SPEED_HZ	9600000
#define SPI_PANEL_COMMAND_LEN	1
static struct spi_device *mdss_spi_client;

int mdss_spi_read_data(u8 reg_addr, u8 *data, u8 len)
{
	int rc = 0;
	u32 max_speed_hz;
	u8 memory_write_reg = 0x2c;
	u8 empty_pack[] = {0x29, 0x29, 0x29};
	struct spi_transfer t[4] = {
		[0] = {
			.tx_buf = &reg_addr,
			.len = 1,
		},
		[1] = {
			.rx_buf = data,
			.len = len,
		},
		[2] = {
			.tx_buf = &empty_pack,
			.len = 3,
		},
		[3] = {
			.tx_buf = &memory_write_reg,
			.len = 1,
		}
	};
	struct spi_message m;

	if (!mdss_spi_client) {
		pr_err("%s: spi client not available\n", __func__);
		return -EINVAL;
	}

	mdss_spi_client->bits_per_word = 8;
	max_speed_hz = mdss_spi_client->max_speed_hz;
	mdss_spi_client->max_speed_hz = MAX_READ_SPEED_HZ;

	spi_message_init(&m);
	spi_message_add_tail(&t[0], &m);
	spi_message_add_tail(&t[1], &m);
	rc = spi_sync(mdss_spi_client, &m);
	if (rc) {
		pr_err("%s: send panel reg failed\n", __func__);
		return rc;
	}

	spi_message_init(&m);
	spi_message_add_tail(&t[2], &m);
	rc = spi_sync(mdss_spi_client, &m);
	if (rc) {
		pr_err("%s: send empty package failed\n", __func__);
		return rc;
	}

	spi_message_init(&m);
	spi_message_add_tail(&t[3], &m);
	rc = spi_sync(mdss_spi_client, &m);
	mdss_spi_client->max_speed_hz = max_speed_hz;
	if (rc) {
		pr_err("%s: send memory write reg failed\n", __func__);
		return rc;
	}

	return rc;
}

int mdss_spi_tx_command(const void *buf)
{
	int rc = 0;
	struct spi_transfer t = {
		.tx_buf = buf,
		.len    = SPI_PANEL_COMMAND_LEN,
	};
	struct spi_message m;

	if (!mdss_spi_client) {
		pr_err("%s: spi client not available\n", __func__);
		return -EINVAL;
	}

	mdss_spi_client->bits_per_word = 8;

	spi_message_init(&m);
	spi_message_add_tail(&t, &m);
	rc = spi_sync(mdss_spi_client, &m);
	if (rc)
		pr_err("%s: send panel command failed\n", __func__);
	return rc;
}

int mdss_spi_tx_parameter(const void *buf, size_t len)
{
	int rc = 0;
	struct spi_transfer t = {
		.tx_buf = buf,
		.len    = len,
	};
	struct spi_message m;

	if (!mdss_spi_client) {
		pr_err("%s: spi client not available\n", __func__);
		return -EINVAL;
	}

	mdss_spi_client->bits_per_word = 8;

	spi_message_init(&m);
	spi_message_add_tail(&t, &m);
	rc = spi_sync(mdss_spi_client, &m);
	if (rc)
		pr_err("%s: send panel parameter failed\n", __func__);

	return rc;
}

int mdss_spi_tx_pixel(const void *buf, size_t len,
		void (*spi_tx_compelet)(void *), void *ctx)
{
	int rc = 0;
	static struct spi_transfer t;
	static struct spi_message m;

	if (!mdss_spi_client) {
		pr_err("%s: spi client not available\n", __func__);
		return -EINVAL;
	}

	mdss_spi_client->bits_per_word = 16;
	t.tx_buf = buf;
	t.len = len;
	spi_message_init(&m);
	m.complete = spi_tx_compelet;
	m.context = ctx;

	spi_message_add_tail(&t, &m);
	rc = spi_async(mdss_spi_client, &m);

	if (rc)
		pr_err("%s: send FrameBuffer data failed\n", __func__);

	return rc;
}

static int mdss_spi_client_probe(struct spi_device *spidev)
{
	int irq;
	int cs;
	int cpha, cpol, cs_high;
	u32 max_speed;

	irq = spidev->irq;
	cs = spidev->chip_select;
	cpha = (spidev->mode & SPI_CPHA) ? 1:0;
	cpol = (spidev->mode & SPI_CPOL) ? 1:0;
	cs_high = (spidev->mode & SPI_CS_HIGH) ? 1:0;
	max_speed = spidev->max_speed_hz;

	pr_debug("cs[%x] CPHA[%x] CPOL[%x] CS_HIGH[%x] Max_speed[%d]\n",
		cs, cpha, cpol, cs_high, max_speed);
	mdss_spi_client = spidev;

	return 0;
}

static const struct of_device_id mdss_spi_dt_match[] = {
	{ .compatible = "qcom,mdss-spi-client" },
	{},
};

static struct spi_driver mdss_spi_client_driver = {
	.probe = mdss_spi_client_probe,
	.driver = {
		.name = "mdss-spi-client",
		.owner  = THIS_MODULE,
		.of_match_table = mdss_spi_dt_match,
	},
};

static int __init mdss_spi_init(void)
{
	int ret;

	ret = spi_register_driver(&mdss_spi_client_driver);
	if (ret) {
		pr_err("register mdss spi client driver failed!\n");
		return ret;
	}

	return 0;
}
module_init(mdss_spi_init);

static void __exit mdss_spi_exit(void)
{
	spi_unregister_driver(&mdss_spi_client_driver);
}
module_exit(mdss_spi_exit);
+22 −0
Original line number Diff line number Diff line
/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 and
 * only version 2 as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#ifndef __MDSS_SPI_CLIENT_H__
#define __MDSS_SPI_CLIENT_H__

int mdss_spi_tx_command(const void *buf);
int mdss_spi_tx_parameter(const void *buf, size_t len);
int mdss_spi_tx_pixel(const void *buf, size_t len,
		void (*spi_tx_compelet)(void *), void *ctx);
int mdss_spi_read_data(u8 reg_addr, u8 *data, u8 len);

#endif /* End of __MDSS_SPI_CLIENT_H__ */