mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-07-22 23:04:43 +00:00
Merge branch 'spi-4.20' into spi-next
This commit is contained in:
commit
4b51c747e4
53 changed files with 3941 additions and 396 deletions
|
@ -1,18 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* SPI init/core code
|
||||
*
|
||||
* Copyright (C) 2005 David Brownell
|
||||
* Copyright (C) 2008 Secret Lab Technologies Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* 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/kernel.h>
|
||||
|
@ -60,6 +51,7 @@ static void spidev_release(struct device *dev)
|
|||
spi->controller->cleanup(spi);
|
||||
|
||||
spi_controller_put(spi->controller);
|
||||
kfree(spi->driver_override);
|
||||
kfree(spi);
|
||||
}
|
||||
|
||||
|
@ -77,6 +69,51 @@ modalias_show(struct device *dev, struct device_attribute *a, char *buf)
|
|||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
static ssize_t driver_override_store(struct device *dev,
|
||||
struct device_attribute *a,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct spi_device *spi = to_spi_device(dev);
|
||||
const char *end = memchr(buf, '\n', count);
|
||||
const size_t len = end ? end - buf : count;
|
||||
const char *driver_override, *old;
|
||||
|
||||
/* We need to keep extra room for a newline when displaying value */
|
||||
if (len >= (PAGE_SIZE - 1))
|
||||
return -EINVAL;
|
||||
|
||||
driver_override = kstrndup(buf, len, GFP_KERNEL);
|
||||
if (!driver_override)
|
||||
return -ENOMEM;
|
||||
|
||||
device_lock(dev);
|
||||
old = spi->driver_override;
|
||||
if (len) {
|
||||
spi->driver_override = driver_override;
|
||||
} else {
|
||||
/* Emptry string, disable driver override */
|
||||
spi->driver_override = NULL;
|
||||
kfree(driver_override);
|
||||
}
|
||||
device_unlock(dev);
|
||||
kfree(old);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t driver_override_show(struct device *dev,
|
||||
struct device_attribute *a, char *buf)
|
||||
{
|
||||
const struct spi_device *spi = to_spi_device(dev);
|
||||
ssize_t len;
|
||||
|
||||
device_lock(dev);
|
||||
len = snprintf(buf, PAGE_SIZE, "%s\n", spi->driver_override ? : "");
|
||||
device_unlock(dev);
|
||||
return len;
|
||||
}
|
||||
static DEVICE_ATTR_RW(driver_override);
|
||||
|
||||
#define SPI_STATISTICS_ATTRS(field, file) \
|
||||
static ssize_t spi_controller_##field##_show(struct device *dev, \
|
||||
struct device_attribute *attr, \
|
||||
|
@ -158,6 +195,7 @@ SPI_STATISTICS_SHOW(transfers_split_maxsize, "%lu");
|
|||
|
||||
static struct attribute *spi_dev_attrs[] = {
|
||||
&dev_attr_modalias.attr,
|
||||
&dev_attr_driver_override.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
|
@ -305,6 +343,10 @@ static int spi_match_device(struct device *dev, struct device_driver *drv)
|
|||
const struct spi_device *spi = to_spi_device(dev);
|
||||
const struct spi_driver *sdrv = to_spi_driver(drv);
|
||||
|
||||
/* Check override first, and if set, only use the named driver */
|
||||
if (spi->driver_override)
|
||||
return strcmp(spi->driver_override, drv->name) == 0;
|
||||
|
||||
/* Attempt an OF style match */
|
||||
if (of_driver_match_device(dev, drv))
|
||||
return 1;
|
||||
|
@ -733,7 +775,9 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
|
|||
enable = !enable;
|
||||
|
||||
if (gpio_is_valid(spi->cs_gpio)) {
|
||||
gpio_set_value(spi->cs_gpio, !enable);
|
||||
/* Honour the SPI_NO_CS flag */
|
||||
if (!(spi->mode & SPI_NO_CS))
|
||||
gpio_set_value(spi->cs_gpio, !enable);
|
||||
/* Some SPI masters need both GPIO CS & slave_select */
|
||||
if ((spi->controller->flags & SPI_MASTER_GPIO_SS) &&
|
||||
spi->controller->set_cs)
|
||||
|
@ -2783,8 +2827,10 @@ int spi_setup(struct spi_device *spi)
|
|||
return -EINVAL;
|
||||
/* help drivers fail *cleanly* when they need options
|
||||
* that aren't supported with their current controller
|
||||
* SPI_CS_WORD has a fallback software implementation,
|
||||
* so it is ignored here.
|
||||
*/
|
||||
bad_bits = spi->mode & ~spi->controller->mode_bits;
|
||||
bad_bits = spi->mode & ~(spi->controller->mode_bits | SPI_CS_WORD);
|
||||
ugly_bits = bad_bits &
|
||||
(SPI_TX_DUAL | SPI_TX_QUAD | SPI_RX_DUAL | SPI_RX_QUAD);
|
||||
if (ugly_bits) {
|
||||
|
@ -2838,6 +2884,35 @@ static int __spi_validate(struct spi_device *spi, struct spi_message *message)
|
|||
if (list_empty(&message->transfers))
|
||||
return -EINVAL;
|
||||
|
||||
/* If an SPI controller does not support toggling the CS line on each
|
||||
* transfer (indicated by the SPI_CS_WORD flag) or we are using a GPIO
|
||||
* for the CS line, we can emulate the CS-per-word hardware function by
|
||||
* splitting transfers into one-word transfers and ensuring that
|
||||
* cs_change is set for each transfer.
|
||||
*/
|
||||
if ((spi->mode & SPI_CS_WORD) && (!(ctlr->mode_bits & SPI_CS_WORD) ||
|
||||
gpio_is_valid(spi->cs_gpio))) {
|
||||
size_t maxsize;
|
||||
int ret;
|
||||
|
||||
maxsize = (spi->bits_per_word + 7) / 8;
|
||||
|
||||
/* spi_split_transfers_maxsize() requires message->spi */
|
||||
message->spi = spi;
|
||||
|
||||
ret = spi_split_transfers_maxsize(ctlr, message, maxsize,
|
||||
GFP_KERNEL);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
list_for_each_entry(xfer, &message->transfers, transfer_list) {
|
||||
/* don't change cs_change on the last entry in the list */
|
||||
if (list_is_last(&xfer->transfer_list, &message->transfers))
|
||||
break;
|
||||
xfer->cs_change = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Half-duplex links include original MicroWire, and ones with
|
||||
* only one data pin like SPI_3WIRE (switches direction) or where
|
||||
* either MOSI or MISO is missing. They can also be caused by
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue