1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * Copyright (C) 2016 Noralf Trønnes
6 #include <linux/backlight.h>
7 #include <linux/dma-buf.h>
8 #include <linux/module.h>
10 #include <linux/spi/spi.h>
11 #include <linux/swab.h>
13 #include <drm/drm_device.h>
14 #include <drm/drm_drv.h>
15 #include <drm/drm_fourcc.h>
16 #include <drm/drm_framebuffer.h>
17 #include <drm/drm_print.h>
18 #include <drm/drm_rect.h>
19 #include <drm/tinydrm/tinydrm-helpers.h>
21 static unsigned int spi_max
;
22 module_param(spi_max
, uint
, 0400);
23 MODULE_PARM_DESC(spi_max
, "Set a lower SPI max transfer size");
25 #if IS_ENABLED(CONFIG_SPI)
28 * tinydrm_spi_max_transfer_size - Determine max SPI transfer size
30 * @max_len: Maximum buffer size needed (optional)
32 * This function returns the maximum size to use for SPI transfers. It checks
33 * the SPI master, the optional @max_len and the module parameter spi_max and
34 * returns the smallest.
37 * Maximum size for SPI transfers
39 size_t tinydrm_spi_max_transfer_size(struct spi_device
*spi
, size_t max_len
)
43 ret
= min(spi_max_transfer_size(spi
), spi
->master
->max_dma_len
);
45 ret
= min(ret
, max_len
);
47 ret
= min_t(size_t, ret
, spi_max
);
54 EXPORT_SYMBOL(tinydrm_spi_max_transfer_size
);
57 * tinydrm_spi_bpw_supported - Check if bits per word is supported
61 * This function checks to see if the SPI master driver supports @bpw.
64 * True if @bpw is supported, false otherwise.
66 bool tinydrm_spi_bpw_supported(struct spi_device
*spi
, u8 bpw
)
68 u32 bpw_mask
= spi
->master
->bits_per_word_mask
;
74 dev_warn_once(&spi
->dev
,
75 "bits_per_word_mask not set, assume 8-bit only\n");
79 if (bpw_mask
& SPI_BPW_MASK(bpw
))
84 EXPORT_SYMBOL(tinydrm_spi_bpw_supported
);
87 tinydrm_dbg_spi_print(struct spi_device
*spi
, struct spi_transfer
*tr
,
88 const void *buf
, int idx
, bool tx
)
90 u32 speed_hz
= tr
->speed_hz
? tr
->speed_hz
: spi
->max_speed_hz
;
93 hex_dump_to_buffer(buf
, tr
->len
, 16,
94 DIV_ROUND_UP(tr
->bits_per_word
, 8),
95 linebuf
, sizeof(linebuf
), false);
98 " tr(%i): speed=%u%s, bpw=%i, len=%u, %s_buf=[%s%s]\n", idx
,
99 speed_hz
> 1000000 ? speed_hz
/ 1000000 : speed_hz
/ 1000,
100 speed_hz
> 1000000 ? "MHz" : "kHz", tr
->bits_per_word
, tr
->len
,
101 tx
? "tx" : "rx", linebuf
, tr
->len
> 16 ? " ..." : "");
104 /* called through tinydrm_dbg_spi_message() */
105 void _tinydrm_dbg_spi_message(struct spi_device
*spi
, struct spi_message
*m
)
107 struct spi_transfer
*tmp
;
110 list_for_each_entry(tmp
, &m
->transfers
, transfer_list
) {
113 tinydrm_dbg_spi_print(spi
, tmp
, tmp
->tx_buf
, i
, true);
115 tinydrm_dbg_spi_print(spi
, tmp
, tmp
->rx_buf
, i
, false);
119 EXPORT_SYMBOL(_tinydrm_dbg_spi_message
);
122 * tinydrm_spi_transfer - SPI transfer helper
124 * @speed_hz: Override speed (optional)
125 * @header: Optional header transfer
126 * @bpw: Bits per word
127 * @buf: Buffer to transfer
128 * @len: Buffer length
130 * This SPI transfer helper breaks up the transfer of @buf into chunks which
131 * the SPI master driver can handle. If the machine is Little Endian and the
132 * SPI master driver doesn't support 16 bits per word, it swaps the bytes and
133 * does a 8-bit transfer.
134 * If @header is set, it is prepended to each SPI message.
137 * Zero on success, negative error code on failure.
139 int tinydrm_spi_transfer(struct spi_device
*spi
, u32 speed_hz
,
140 struct spi_transfer
*header
, u8 bpw
, const void *buf
,
143 struct spi_transfer tr
= {
144 .bits_per_word
= bpw
,
145 .speed_hz
= speed_hz
,
147 struct spi_message m
;
148 u16
*swap_buf
= NULL
;
153 if (WARN_ON_ONCE(bpw
!= 8 && bpw
!= 16))
156 max_chunk
= tinydrm_spi_max_transfer_size(spi
, 0);
158 if (drm_debug
& DRM_UT_DRIVER
)
159 pr_debug("[drm:%s] bpw=%u, max_chunk=%zu, transfers:\n",
160 __func__
, bpw
, max_chunk
);
162 if (bpw
== 16 && !tinydrm_spi_bpw_supported(spi
, 16)) {
163 tr
.bits_per_word
= 8;
164 if (tinydrm_machine_little_endian()) {
165 swap_buf
= kmalloc(min(len
, max_chunk
), GFP_KERNEL
);
171 spi_message_init(&m
);
173 spi_message_add_tail(header
, &m
);
174 spi_message_add_tail(&tr
, &m
);
177 chunk
= min(len
, max_chunk
);
183 const u16
*buf16
= buf
;
186 for (i
= 0; i
< chunk
/ 2; i
++)
187 swap_buf
[i
] = swab16(buf16
[i
]);
189 tr
.tx_buf
= swap_buf
;
195 tinydrm_dbg_spi_message(spi
, &m
);
196 ret
= spi_sync(spi
, &m
);
203 EXPORT_SYMBOL(tinydrm_spi_transfer
);
205 #endif /* CONFIG_SPI */
207 MODULE_LICENSE("GPL");