Commit 2962db71 authored by Noralf Trønnes's avatar Noralf Trønnes Committed by Greg Kroah-Hartman

staging/fbtft: Remove fbtft_device

Commit c440eee1 ("Staging: fbtft: Switch to the gpio descriptor
interface") removed the gpio code from fbtft_device rendering it useless.

fbtft_device is a module that was used on the Raspberry Pi to dynamically
add fbtft devices when the Pi didn't have Device Tree support.
Just remove the module since it's the responsibility of Device Tree, ACPI
or platform code to add devices.

Fixes: c440eee1 ("Staging: fbtft: Switch to the gpio descriptor interface")
Signed-off-by: default avatarNoralf Trønnes <noralf@tronnes.org>
Link: https://lore.kernel.org/r/20190917171843.10334-2-noralf@tronnes.orgSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 63f2b167
......@@ -205,7 +205,3 @@ config FB_FLEX
depends on FB_TFT
help
Generic Framebuffer support for TFT LCD displays.
config FB_TFT_FBTFT_DEVICE
tristate "Module to for adding FBTFT devices"
depends on FB_TFT
......@@ -37,6 +37,3 @@ obj-$(CONFIG_FB_TFT_UC1701) += fb_uc1701.o
obj-$(CONFIG_FB_TFT_UPD161704) += fb_upd161704.o
obj-$(CONFIG_FB_TFT_WATTEROTT) += fb_watterott.o
obj-$(CONFIG_FB_FLEX) += flexfb.o
# Device modules
obj-$(CONFIG_FB_TFT_FBTFT_DEVICE) += fbtft_device.o
// SPDX-License-Identifier: GPL-2.0+
/*
*
* Copyright (C) 2013, Noralf Tronnes
*/
#define pr_fmt(fmt) "fbtft_device: " fmt
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/gpio/consumer.h>
#include <linux/spi/spi.h>
#include <video/mipi_display.h>
#include "fbtft.h"
#define MAX_GPIOS 32
static struct spi_device *spi_device;
static struct platform_device *p_device;
static char *name;
module_param(name, charp, 0000);
MODULE_PARM_DESC(name,
"Devicename (required). name=list => list all supported devices.");
static unsigned int rotate;
module_param(rotate, uint, 0000);
MODULE_PARM_DESC(rotate,
"Angle to rotate display counter clockwise: 0, 90, 180, 270");
static unsigned int busnum;
module_param(busnum, uint, 0000);
MODULE_PARM_DESC(busnum, "SPI bus number (default=0)");
static unsigned int cs;
module_param(cs, uint, 0000);
MODULE_PARM_DESC(cs, "SPI chip select (default=0)");
static unsigned int speed;
module_param(speed, uint, 0000);
MODULE_PARM_DESC(speed, "SPI speed (override device default)");
static int mode = -1;
module_param(mode, int, 0000);
MODULE_PARM_DESC(mode, "SPI mode (override device default)");
static unsigned int fps;
module_param(fps, uint, 0000);
MODULE_PARM_DESC(fps, "Frames per second (override driver default)");
static char *gamma;
module_param(gamma, charp, 0000);
MODULE_PARM_DESC(gamma,
"String representation of Gamma Curve(s). Driver specific.");
static int txbuflen;
module_param(txbuflen, int, 0000);
MODULE_PARM_DESC(txbuflen, "txbuflen (override driver default)");
static int bgr = -1;
module_param(bgr, int, 0000);
MODULE_PARM_DESC(bgr,
"BGR bit (supported by some drivers).");
static unsigned int startbyte;
module_param(startbyte, uint, 0000);
MODULE_PARM_DESC(startbyte, "Sets the Start byte used by some SPI displays.");
static bool custom;
module_param(custom, bool, 0000);
MODULE_PARM_DESC(custom, "Add a custom display device. Use speed= argument to make it a SPI device, else platform_device");
static unsigned int width;
module_param(width, uint, 0000);
MODULE_PARM_DESC(width, "Display width, used with the custom argument");
static unsigned int height;
module_param(height, uint, 0000);
MODULE_PARM_DESC(height, "Display height, used with the custom argument");
static unsigned int buswidth = 8;
module_param(buswidth, uint, 0000);
MODULE_PARM_DESC(buswidth, "Display bus width, used with the custom argument");
static s16 init[FBTFT_MAX_INIT_SEQUENCE];
static int init_num;
module_param_array(init, short, &init_num, 0000);
MODULE_PARM_DESC(init, "Init sequence, used with the custom argument");
static unsigned long debug;
module_param(debug, ulong, 0000);
MODULE_PARM_DESC(debug,
"level: 0-7 (the remaining 29 bits is for advanced usage)");
static unsigned int verbose = 3;
module_param(verbose, uint, 0000);
MODULE_PARM_DESC(verbose,
"0 silent, >1 show devices, >2 show devices before (default=3)");
struct fbtft_device_display {
char *name;
struct spi_board_info *spi;
struct platform_device *pdev;
};
static void fbtft_device_pdev_release(struct device *dev);
static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len);
static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
int xs, int ys, int xe, int ye);
#define ADAFRUIT18_GAMMA \
"02 1c 07 12 37 32 29 2d 29 25 2B 39 00 01 03 10\n" \
"03 1d 07 06 2E 2C 29 2D 2E 2E 37 3F 00 00 02 10"
#define CBERRY28_GAMMA \
"D0 00 14 15 13 2C 42 43 4E 09 16 14 18 21\n" \
"D0 00 14 15 13 0B 43 55 53 0C 17 14 23 20"
static const s16 cberry28_init_sequence[] = {
/* turn off sleep mode */
-1, MIPI_DCS_EXIT_SLEEP_MODE,
-2, 120,
/* set pixel format to RGB-565 */
-1, MIPI_DCS_SET_PIXEL_FORMAT, MIPI_DCS_PIXEL_FMT_16BIT,
-1, 0xB2, 0x0C, 0x0C, 0x00, 0x33, 0x33,
/*
* VGH = 13.26V
* VGL = -10.43V
*/
-1, 0xB7, 0x35,
/*
* VDV and VRH register values come from command write
* (instead of NVM)
*/
-1, 0xC2, 0x01, 0xFF,
/*
* VAP = 4.7V + (VCOM + VCOM offset + 0.5 * VDV)
* VAN = -4.7V + (VCOM + VCOM offset + 0.5 * VDV)
*/
-1, 0xC3, 0x17,
/* VDV = 0V */
-1, 0xC4, 0x20,
/* VCOM = 0.675V */
-1, 0xBB, 0x17,
/* VCOM offset = 0V */
-1, 0xC5, 0x20,
/*
* AVDD = 6.8V
* AVCL = -4.8V
* VDS = 2.3V
*/
-1, 0xD0, 0xA4, 0xA1,
-1, MIPI_DCS_SET_DISPLAY_ON,
-3,
};
static const s16 hy28b_init_sequence[] = {
-1, 0x00e7, 0x0010, -1, 0x0000, 0x0001,
-1, 0x0001, 0x0100, -1, 0x0002, 0x0700,
-1, 0x0003, 0x1030, -1, 0x0004, 0x0000,
-1, 0x0008, 0x0207, -1, 0x0009, 0x0000,
-1, 0x000a, 0x0000, -1, 0x000c, 0x0001,
-1, 0x000d, 0x0000, -1, 0x000f, 0x0000,
-1, 0x0010, 0x0000, -1, 0x0011, 0x0007,
-1, 0x0012, 0x0000, -1, 0x0013, 0x0000,
-2, 50, -1, 0x0010, 0x1590, -1, 0x0011,
0x0227, -2, 50, -1, 0x0012, 0x009c, -2, 50,
-1, 0x0013, 0x1900, -1, 0x0029, 0x0023,
-1, 0x002b, 0x000e, -2, 50,
-1, 0x0020, 0x0000, -1, 0x0021, 0x0000,
-2, 50, -1, 0x0050, 0x0000,
-1, 0x0051, 0x00ef, -1, 0x0052, 0x0000,
-1, 0x0053, 0x013f, -1, 0x0060, 0xa700,
-1, 0x0061, 0x0001, -1, 0x006a, 0x0000,
-1, 0x0080, 0x0000, -1, 0x0081, 0x0000,
-1, 0x0082, 0x0000, -1, 0x0083, 0x0000,
-1, 0x0084, 0x0000, -1, 0x0085, 0x0000,
-1, 0x0090, 0x0010, -1, 0x0092, 0x0000,
-1, 0x0093, 0x0003, -1, 0x0095, 0x0110,
-1, 0x0097, 0x0000, -1, 0x0098, 0x0000,
-1, 0x0007, 0x0133, -1, 0x0020, 0x0000,
-1, 0x0021, 0x0000, -2, 100, -3 };
#define HY28B_GAMMA \
"04 1F 4 7 7 0 7 7 6 0\n" \
"0F 00 1 7 4 0 0 0 6 7"
static const s16 pitft_init_sequence[] = {
-1, MIPI_DCS_SOFT_RESET,
-2, 5,
-1, MIPI_DCS_SET_DISPLAY_OFF,
-1, 0xEF, 0x03, 0x80, 0x02,
-1, 0xCF, 0x00, 0xC1, 0x30,
-1, 0xED, 0x64, 0x03, 0x12, 0x81,
-1, 0xE8, 0x85, 0x00, 0x78,
-1, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
-1, 0xF7, 0x20,
-1, 0xEA, 0x00, 0x00,
-1, 0xC0, 0x23,
-1, 0xC1, 0x10,
-1, 0xC5, 0x3E, 0x28,
-1, 0xC7, 0x86,
-1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
-1, 0xB1, 0x00, 0x18,
-1, 0xB6, 0x08, 0x82, 0x27,
-1, 0xF2, 0x00,
-1, MIPI_DCS_SET_GAMMA_CURVE, 0x01,
-1, 0xE0, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,
0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
-1, 0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,
0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
-1, MIPI_DCS_EXIT_SLEEP_MODE,
-2, 100,
-1, MIPI_DCS_SET_DISPLAY_ON,
-2, 20,
-3
};
static const s16 waveshare32b_init_sequence[] = {
-1, 0xCB, 0x39, 0x2C, 0x00, 0x34, 0x02,
-1, 0xCF, 0x00, 0xC1, 0x30,
-1, 0xE8, 0x85, 0x00, 0x78,
-1, 0xEA, 0x00, 0x00,
-1, 0xED, 0x64, 0x03, 0x12, 0x81,
-1, 0xF7, 0x20,
-1, 0xC0, 0x23,
-1, 0xC1, 0x10,
-1, 0xC5, 0x3E, 0x28,
-1, 0xC7, 0x86,
-1, MIPI_DCS_SET_ADDRESS_MODE, 0x28,
-1, MIPI_DCS_SET_PIXEL_FORMAT, 0x55,
-1, 0xB1, 0x00, 0x18,
-1, 0xB6, 0x08, 0x82, 0x27,
-1, 0xF2, 0x00,
-1, MIPI_DCS_SET_GAMMA_CURVE, 0x01,
-1, 0xE0, 0x0F, 0x31, 0x2B, 0x0C, 0x0E, 0x08, 0x4E,
0xF1, 0x37, 0x07, 0x10, 0x03, 0x0E, 0x09, 0x00,
-1, 0xE1, 0x00, 0x0E, 0x14, 0x03, 0x11, 0x07, 0x31,
0xC1, 0x48, 0x08, 0x0F, 0x0C, 0x31, 0x36, 0x0F,
-1, MIPI_DCS_EXIT_SLEEP_MODE,
-2, 120,
-1, MIPI_DCS_SET_DISPLAY_ON,
-1, MIPI_DCS_WRITE_MEMORY_START,
-3
};
#define PIOLED_GAMMA "0 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 2 " \
"2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 " \
"3 3 3 4 4 4 4 4 4 4 4 4 4 4 4"
/* Supported displays in alphabetical order */
static struct fbtft_device_display displays[] = {
{
.name = "adafruit18",
.spi = &(struct spi_board_info) {
.modalias = "fb_st7735r",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.gamma = ADAFRUIT18_GAMMA,
}
}
}, {
.name = "adafruit18_green",
.spi = &(struct spi_board_info) {
.modalias = "fb_st7735r",
.max_speed_hz = 4000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
.fbtftops.set_addr_win =
adafruit18_green_tab_set_addr_win,
},
.bgr = true,
.gamma = ADAFRUIT18_GAMMA,
}
}
}, {
.name = "adafruit22",
.spi = &(struct spi_board_info) {
.modalias = "fb_hx8340bn",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 9,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "adafruit22a",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9340",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "adafruit28",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9341",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "adafruit13m",
.spi = &(struct spi_board_info) {
.modalias = "fb_ssd1306",
.max_speed_hz = 16000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
}
}
}, {
.name = "admatec_c-berry28",
.spi = &(struct spi_board_info) {
.modalias = "fb_st7789v",
.max_speed_hz = 48000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
.init_sequence = cberry28_init_sequence,
},
.gamma = CBERRY28_GAMMA,
}
}
}, {
.name = "agm1264k-fl",
.pdev = &(struct platform_device) {
.name = "fb_agm1264k-fl",
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = FBTFT_ONBOARD_BACKLIGHT,
},
},
}
}
}, {
.name = "dogs102",
.spi = &(struct spi_board_info) {
.modalias = "fb_uc1701",
.max_speed_hz = 8000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
.bgr = true,
}
}
}, {
.name = "er_tftm050_2",
.spi = &(struct spi_board_info) {
.modalias = "fb_ra8875",
.max_speed_hz = 5000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
.width = 480,
.height = 272,
},
.bgr = true,
}
}
}, {
.name = "er_tftm070_5",
.spi = &(struct spi_board_info) {
.modalias = "fb_ra8875",
.max_speed_hz = 5000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
.width = 800,
.height = 480,
},
.bgr = true,
}
}
}, {
.name = "ew24ha0",
.spi = &(struct spi_board_info) {
.modalias = "fb_uc1611",
.max_speed_hz = 32000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
}
}
}, {
.name = "ew24ha0_9bit",
.spi = &(struct spi_board_info) {
.modalias = "fb_uc1611",
.max_speed_hz = 32000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 9,
},
}
}
}, {
.name = "flexfb",
.spi = &(struct spi_board_info) {
.modalias = "flexfb",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
}
}, {
.name = "flexpfb",
.pdev = &(struct platform_device) {
.name = "flexpfb",
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
}
}
}, {
.name = "freetronicsoled128",
.spi = &(struct spi_board_info) {
.modalias = "fb_ssd1351",
.max_speed_hz = 20000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = FBTFT_ONBOARD_BACKLIGHT,
},
.bgr = true,
}
}
}, {
.name = "hx8353d",
.spi = &(struct spi_board_info) {
.modalias = "fb_hx8353d",
.max_speed_hz = 16000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
}
}
}, {
.name = "hy28a",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9320",
.max_speed_hz = 32000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.startbyte = 0x70,
.bgr = true,
}
}
}, {
.name = "hy28b",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9325",
.max_speed_hz = 48000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
.init_sequence = hy28b_init_sequence,
},
.startbyte = 0x70,
.bgr = true,
.fps = 50,
.gamma = HY28B_GAMMA,
}
}
}, {
.name = "ili9481",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9481",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.regwidth = 16,
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "itdb24",
.pdev = &(struct platform_device) {
.name = "fb_s6d1121",
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = false,
},
}
}
}, {
.name = "itdb28",
.pdev = &(struct platform_device) {
.name = "fb_ili9325",
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
},
}
}
}, {
.name = "itdb28_spi",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9325",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "mi0283qt-2",
.spi = &(struct spi_board_info) {
.modalias = "fb_hx8347d",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.startbyte = 0x70,
.bgr = true,
}
}
}, {
.name = "mi0283qt-9a",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9341",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 9,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "mi0283qt-v2",
.spi = &(struct spi_board_info) {
.modalias = "fb_watterott",
.max_speed_hz = 4000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
}
}
}, {
.name = "nokia3310",
.spi = &(struct spi_board_info) {
.modalias = "fb_pcd8544",
.max_speed_hz = 400000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
}
}
}, {
.name = "nokia3310a",
.spi = &(struct spi_board_info) {
.modalias = "fb_tls8204",
.max_speed_hz = 1000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
}
}
}, {
.name = "nokia5110",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9163",
.max_speed_hz = 12000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "piscreen",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9486",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.regwidth = 16,
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "pitft",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9340",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.chip_select = 0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
.init_sequence = pitft_init_sequence,
},
.bgr = true,
}
}
}, {
.name = "pioled",
.spi = &(struct spi_board_info) {
.modalias = "fb_ssd1351",
.max_speed_hz = 20000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
.bgr = true,
.gamma = PIOLED_GAMMA
}
}
}, {
.name = "rpi-display",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9341",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "s6d02a1",
.spi = &(struct spi_board_info) {
.modalias = "fb_s6d02a1",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "sainsmart18",
.spi = &(struct spi_board_info) {
.modalias = "fb_st7735r",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
}
}
}, {
.name = "sainsmart32",
.pdev = &(struct platform_device) {
.name = "fb_ssd1289",
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 16,
.txbuflen = -2, /* disable buffer */
.backlight = 1,
.fbtftops.write = write_gpio16_wr_slow,
},
.bgr = true,
},
},
}
}, {
.name = "sainsmart32_fast",
.pdev = &(struct platform_device) {
.name = "fb_ssd1289",
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 16,
.txbuflen = -2, /* disable buffer */
.backlight = 1,
},
.bgr = true,
},
},
}
}, {
.name = "sainsmart32_latched",
.pdev = &(struct platform_device) {
.name = "fb_ssd1289",
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 16,
.txbuflen = -2, /* disable buffer */
.backlight = 1,
.fbtftops.write =
fbtft_write_gpio16_wr_latched,
},
.bgr = true,
},
},
}
}, {
.name = "sainsmart32_spi",
.spi = &(struct spi_board_info) {
.modalias = "fb_ssd1289",
.max_speed_hz = 16000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "spidev",
.spi = &(struct spi_board_info) {
.modalias = "spidev",
.max_speed_hz = 500000,
.bus_num = 0,
.chip_select = 0,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
}
}
}, {
.name = "ssd1331",
.spi = &(struct spi_board_info) {
.modalias = "fb_ssd1331",
.max_speed_hz = 20000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
}
}
}, {
.name = "tinylcd35",
.spi = &(struct spi_board_info) {
.modalias = "fb_tinylcd",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "tm022hdh26",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9341",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "tontec35_9481", /* boards before 02 July 2014 */
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9481",
.max_speed_hz = 128000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "tontec35_9486", /* boards after 02 July 2014 */
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9486",
.max_speed_hz = 128000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
},
.bgr = true,
}
}
}, {
.name = "upd161704",
.spi = &(struct spi_board_info) {
.modalias = "fb_upd161704",
.max_speed_hz = 32000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
}
}
}, {
.name = "waveshare32b",
.spi = &(struct spi_board_info) {
.modalias = "fb_ili9340",
.max_speed_hz = 48000000,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
.backlight = 1,
.init_sequence =
waveshare32b_init_sequence,
},
.bgr = true,
}
}
}, {
.name = "waveshare22",
.spi = &(struct spi_board_info) {
.modalias = "fb_bd663474",
.max_speed_hz = 32000000,
.mode = SPI_MODE_3,
.platform_data = &(struct fbtft_platform_data) {
.display = {
.buswidth = 8,
},
}
}
}, {
/* This should be the last item.
* Used with the custom argument
*/
.name = "",
.spi = &(struct spi_board_info) {
.modalias = "",
.max_speed_hz = 0,
.mode = SPI_MODE_0,
.platform_data = &(struct fbtft_platform_data) {
}
},
.pdev = &(struct platform_device) {
.name = "",
.id = 0,
.dev = {
.release = fbtft_device_pdev_release,
.platform_data = &(struct fbtft_platform_data) {
},
},
},
}
};
static int write_gpio16_wr_slow(struct fbtft_par *par, void *buf, size_t len)
{
u16 data;
int i;
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
static u16 prev_data;
#endif
fbtft_par_dbg_hex(DEBUG_WRITE, par, par->info->device, u8, buf, len,
"%s(len=%zu): ", __func__, len);
while (len) {
data = *(u16 *)buf;
/* Start writing by pulling down /WR */
gpiod_set_value(par->gpio.wr, 0);
/* Set data */
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
if (data == prev_data) {
gpiod_set_value(par->gpio.wr, 0); /* used as delay */
} else {
for (i = 0; i < 16; i++) {
if ((data & 1) != (prev_data & 1))
gpiod_set_value(par->gpio.db[i],
data & 1);
data >>= 1;
prev_data >>= 1;
}
}
#else
for (i = 0; i < 16; i++) {
gpiod_set_value(par->gpio.db[i], data & 1);
data >>= 1;
}
#endif
/* Pullup /WR */
gpiod_set_value(par->gpio.wr, 1);
#ifndef DO_NOT_OPTIMIZE_FBTFT_WRITE_GPIO
prev_data = *(u16 *)buf;
#endif
buf += 2;
len -= 2;
}
return 0;
}
static void adafruit18_green_tab_set_addr_win(struct fbtft_par *par,
int xs, int ys, int xe, int ye)
{
write_reg(par, 0x2A, 0, xs + 2, 0, xe + 2);
write_reg(par, 0x2B, 0, ys + 1, 0, ye + 1);
write_reg(par, 0x2C);
}
static void fbtft_device_pdev_release(struct device *dev)
{
/* Needed to silence this message:
* Device 'xxx' does not have a release() function,
* it is broken and must be fixed
*/
}
static int spi_device_found(struct device *dev, void *data)
{
struct spi_device *spi = to_spi_device(dev);
dev_info(dev, "%s %s %dkHz %d bits mode=0x%02X\n", spi->modalias,
dev_name(dev), spi->max_speed_hz / 1000, spi->bits_per_word,
spi->mode);
return 0;
}
static void pr_spi_devices(void)
{
pr_debug("SPI devices registered:\n");
bus_for_each_dev(&spi_bus_type, NULL, NULL, spi_device_found);
}
static int p_device_found(struct device *dev, void *data)
{
struct platform_device
*pdev = to_platform_device(dev);
if (strstr(pdev->name, "fb"))
dev_info(dev, "%s id=%d pdata? %s\n", pdev->name, pdev->id,
pdev->dev.platform_data ? "yes" : "no");
return 0;
}
static void pr_p_devices(void)
{
pr_debug("'fb' Platform devices registered:\n");
bus_for_each_dev(&platform_bus_type, NULL, NULL, p_device_found);
}
#ifdef MODULE
static void fbtft_device_spi_delete(struct spi_master *master, unsigned int cs)
{
struct device *dev;
char str[32];
snprintf(str, sizeof(str), "%s.%u", dev_name(&master->dev), cs);
dev = bus_find_device_by_name(&spi_bus_type, NULL, str);
if (dev) {
if (verbose)
dev_info(dev, "Deleting %s\n", str);
device_del(dev);
}
}
static int fbtft_device_spi_device_register(struct spi_board_info *spi)
{
struct spi_master *master;
master = spi_busnum_to_master(spi->bus_num);
if (!master) {
pr_err("spi_busnum_to_master(%d) returned NULL\n",
spi->bus_num);
return -EINVAL;
}
/* make sure it's available */
fbtft_device_spi_delete(master, spi->chip_select);
spi_device = spi_new_device(master, spi);
put_device(&master->dev);
if (!spi_device) {
dev_err(&master->dev, "spi_new_device() returned NULL\n");
return -EPERM;
}
return 0;
}
#else
static int fbtft_device_spi_device_register(struct spi_board_info *spi)
{
return spi_register_board_info(spi, 1);
}
#endif
static int __init fbtft_device_init(void)
{
struct spi_board_info *spi = NULL;
struct fbtft_platform_data *pdata;
bool found = false;
int i = 0;
int ret = 0;
if (!name) {
#ifdef MODULE
pr_err("missing module parameter: 'name'\n");
return -EINVAL;
#else
return 0;
#endif
}
if (init_num > FBTFT_MAX_INIT_SEQUENCE) {
pr_err("init parameter: exceeded max array size: %d\n",
FBTFT_MAX_INIT_SEQUENCE);
return -EINVAL;
}
if (verbose > 2) {
pr_spi_devices(); /* print list of registered SPI devices */
pr_p_devices(); /* print list of 'fb' platform devices */
}
pr_debug("name='%s', busnum=%d, cs=%d\n", name, busnum, cs);
if (rotate > 0 && rotate < 4) {
rotate = (4 - rotate) * 90;
pr_warn("argument 'rotate' should be an angle. Values 1-3 is deprecated. Setting it to %d.\n",
rotate);
}
if (rotate != 0 && rotate != 90 && rotate != 180 && rotate != 270) {
pr_warn("argument 'rotate' illegal value: %d. Setting it to 0.\n",
rotate);
rotate = 0;
}
/* name=list lists all supported displays */
if (strcmp(name, "list") == 0) {
pr_info("Supported displays:\n");
for (i = 0; i < ARRAY_SIZE(displays); i++)
pr_info("%s\n", displays[i].name);
return -ECANCELED;
}
if (custom) {
i = ARRAY_SIZE(displays) - 1;
displays[i].name = name;
if (speed == 0) {
displays[i].pdev->name = name;
displays[i].spi = NULL;
} else {
size_t len;
len = strlcpy(displays[i].spi->modalias, name,
SPI_NAME_SIZE);
if (len >= SPI_NAME_SIZE)
pr_warn("modalias (name) truncated to: %s\n",
displays[i].spi->modalias);
displays[i].pdev = NULL;
}
}
for (i = 0; i < ARRAY_SIZE(displays); i++) {
if (strncmp(name, displays[i].name, SPI_NAME_SIZE) == 0) {
if (displays[i].spi) {
spi = displays[i].spi;
spi->chip_select = cs;
spi->bus_num = busnum;
if (speed)
spi->max_speed_hz = speed;
if (mode != -1)
spi->mode = mode;
pdata = (void *)spi->platform_data;
} else if (displays[i].pdev) {
p_device = displays[i].pdev;
pdata = p_device->dev.platform_data;
} else {
pr_err("broken displays array\n");
return -EINVAL;
}
pdata->rotate = rotate;
if (bgr == 0)
pdata->bgr = false;
else if (bgr == 1)
pdata->bgr = true;
if (startbyte)
pdata->startbyte = startbyte;
if (gamma)
pdata->gamma = gamma;
pdata->display.debug = debug;
if (fps)
pdata->fps = fps;
if (txbuflen)
pdata->txbuflen = txbuflen;
if (init_num)
pdata->display.init_sequence = init;
if (custom) {
pdata->display.width = width;
pdata->display.height = height;
pdata->display.buswidth = buswidth;
pdata->display.backlight = 1;
}
if (displays[i].spi) {
ret = fbtft_device_spi_device_register(spi);
if (ret) {
pr_err("failed to register SPI device\n");
return ret;
}
} else {
ret = platform_device_register(p_device);
if (ret < 0) {
pr_err("platform_device_register() returned %d\n",
ret);
return ret;
}
}
found = true;
break;
}
}
if (!found) {
pr_err("display not supported: '%s'\n", name);
return -EINVAL;
}
if (spi_device && (verbose > 1))
pr_spi_devices();
if (p_device && (verbose > 1))
pr_p_devices();
return 0;
}
static void __exit fbtft_device_exit(void)
{
if (spi_device) {
device_del(&spi_device->dev);
kfree(spi_device);
}
if (p_device)
platform_device_unregister(p_device);
}
arch_initcall(fbtft_device_init);
module_exit(fbtft_device_exit);
MODULE_DESCRIPTION("Add a FBTFT device.");
MODULE_AUTHOR("Noralf Tronnes");
MODULE_LICENSE("GPL");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment