Commit 542d0f60 authored by David S. Miller's avatar David S. Miller
Browse files

Merge tag 'linux-can-fixes-for-5.5-20200102' of...

Merge tag 'linux-can-fixes-for-5.5-20200102' of git://git.kernel.org/pub/scm/linux/kernel/git/mkl/linux-can



Marc Kleine-Budde says:

====================
pull-request: can 2020-01-02

this is a pull request of 9 patches for net/master.

The first 5 patches target all the tcan4x5x driver. The first 3 patches
of them are by Dan Murphy and Sean Nyekjaer and improve the device
initialization (power on, reset and get device out of standby before
register access). The next patch is by Dan Murphy and disables the INH
pin device-state if the GPIO is unavailable. The last patch for the
tcan4x5x driver is by Gustavo A. R. Silva and fixes an inconsistent
PTR_ERR check in the tcan4x5x_parse_config() function.

The next patch is by Oliver Hartkopp and targets the generic CAN device
infrastructure. It ensures that an initialized headroom in outgoing CAN
sk_buffs (e.g. if injected by AF_PACKET).

The last 2 patches are by Johan Hovold and fix the kvaser_usb and gs_usb
drivers by always using the current alternate setting not blindly the
first one.
====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents c72a0bc0 2d77bd61
Loading
Loading
Loading
Loading
+53 −10
Original line number Diff line number Diff line
@@ -102,6 +102,7 @@
#define TCAN4X5X_MODE_NORMAL BIT(7)

#define TCAN4X5X_DISABLE_WAKE_MSK	(BIT(31) | BIT(30))
#define TCAN4X5X_DISABLE_INH_MSK	BIT(9)

#define TCAN4X5X_SW_RESET BIT(2)

@@ -166,6 +167,28 @@ static void tcan4x5x_check_wake(struct tcan4x5x_priv *priv)
	}
}

static int tcan4x5x_reset(struct tcan4x5x_priv *priv)
{
	int ret = 0;

	if (priv->reset_gpio) {
		gpiod_set_value(priv->reset_gpio, 1);

		/* tpulse_width minimum 30us */
		usleep_range(30, 100);
		gpiod_set_value(priv->reset_gpio, 0);
	} else {
		ret = regmap_write(priv->regmap, TCAN4X5X_CONFIG,
				   TCAN4X5X_SW_RESET);
		if (ret)
			return ret;
	}

	usleep_range(700, 1000);

	return ret;
}

static int regmap_spi_gather_write(void *context, const void *reg,
				   size_t reg_len, const void *val,
				   size_t val_len)
@@ -348,14 +371,23 @@ static int tcan4x5x_disable_wake(struct m_can_classdev *cdev)
				  TCAN4X5X_DISABLE_WAKE_MSK, 0x00);
}

static int tcan4x5x_disable_state(struct m_can_classdev *cdev)
{
	struct tcan4x5x_priv *tcan4x5x = cdev->device_data;

	return regmap_update_bits(tcan4x5x->regmap, TCAN4X5X_CONFIG,
				  TCAN4X5X_DISABLE_INH_MSK, 0x01);
}

static int tcan4x5x_parse_config(struct m_can_classdev *cdev)
{
	struct tcan4x5x_priv *tcan4x5x = cdev->device_data;
	int ret;

	tcan4x5x->device_wake_gpio = devm_gpiod_get(cdev->dev, "device-wake",
						    GPIOD_OUT_HIGH);
	if (IS_ERR(tcan4x5x->device_wake_gpio)) {
		if (PTR_ERR(tcan4x5x->power) == -EPROBE_DEFER)
		if (PTR_ERR(tcan4x5x->device_wake_gpio) == -EPROBE_DEFER)
			return -EPROBE_DEFER;

		tcan4x5x_disable_wake(cdev);
@@ -366,18 +398,17 @@ static int tcan4x5x_parse_config(struct m_can_classdev *cdev)
	if (IS_ERR(tcan4x5x->reset_gpio))
		tcan4x5x->reset_gpio = NULL;

	usleep_range(700, 1000);
	ret = tcan4x5x_reset(tcan4x5x);
	if (ret)
		return ret;

	tcan4x5x->device_state_gpio = devm_gpiod_get_optional(cdev->dev,
							      "device-state",
							      GPIOD_IN);
	if (IS_ERR(tcan4x5x->device_state_gpio))
	if (IS_ERR(tcan4x5x->device_state_gpio)) {
		tcan4x5x->device_state_gpio = NULL;

	tcan4x5x->power = devm_regulator_get_optional(cdev->dev,
						      "vsup");
	if (PTR_ERR(tcan4x5x->power) == -EPROBE_DEFER)
		return -EPROBE_DEFER;
		tcan4x5x_disable_state(cdev);
	}

	return 0;
}
@@ -412,6 +443,12 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
	if (!priv)
		return -ENOMEM;

	priv->power = devm_regulator_get_optional(&spi->dev, "vsup");
	if (PTR_ERR(priv->power) == -EPROBE_DEFER)
		return -EPROBE_DEFER;
	else
		priv->power = NULL;

	mcan_class->device_data = priv;

	m_can_class_get_clocks(mcan_class);
@@ -451,11 +488,17 @@ static int tcan4x5x_can_probe(struct spi_device *spi)
	priv->regmap = devm_regmap_init(&spi->dev, &tcan4x5x_bus,
					&spi->dev, &tcan4x5x_regmap);

	ret = tcan4x5x_parse_config(mcan_class);
	ret = tcan4x5x_power_enable(priv->power, 1);
	if (ret)
		goto out_clk;

	tcan4x5x_power_enable(priv->power, 1);
	ret = tcan4x5x_parse_config(mcan_class);
	if (ret)
		goto out_power;

	ret = tcan4x5x_init(mcan_class);
	if (ret)
		goto out_power;

	ret = m_can_class_register(mcan_class);
	if (ret)
+10 −11
Original line number Diff line number Diff line
@@ -381,13 +381,12 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota)
	struct net_device *dev = napi->dev;
	struct mscan_regs __iomem *regs = priv->reg_base;
	struct net_device_stats *stats = &dev->stats;
	int npackets = 0;
	int ret = 1;
	int work_done = 0;
	struct sk_buff *skb;
	struct can_frame *frame;
	u8 canrflg;

	while (npackets < quota) {
	while (work_done < quota) {
		canrflg = in_8(&regs->canrflg);
		if (!(canrflg & (MSCAN_RXF | MSCAN_ERR_IF)))
			break;
@@ -408,18 +407,18 @@ static int mscan_rx_poll(struct napi_struct *napi, int quota)

		stats->rx_packets++;
		stats->rx_bytes += frame->can_dlc;
		npackets++;
		work_done++;
		netif_receive_skb(skb);
	}

	if (!(in_8(&regs->canrflg) & (MSCAN_RXF | MSCAN_ERR_IF))) {
		napi_complete(&priv->napi);
	if (work_done < quota) {
		if (likely(napi_complete_done(&priv->napi, work_done))) {
			clear_bit(F_RX_PROGRESS, &priv->flags);
			if (priv->can.state < CAN_STATE_BUS_OFF)
				out_8(&regs->canrier, priv->shadow_canrier);
		ret = 0;
		}
	return ret;
	}
	return work_done;
}

static irqreturn_t mscan_isr(int irq, void *dev_id)
+2 −2
Original line number Diff line number Diff line
@@ -918,7 +918,7 @@ static int gs_usb_probe(struct usb_interface *intf,
			     GS_USB_BREQ_HOST_FORMAT,
			     USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
			     1,
			     intf->altsetting[0].desc.bInterfaceNumber,
			     intf->cur_altsetting->desc.bInterfaceNumber,
			     hconf,
			     sizeof(*hconf),
			     1000);
@@ -941,7 +941,7 @@ static int gs_usb_probe(struct usb_interface *intf,
			     GS_USB_BREQ_DEVICE_CONFIG,
			     USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
			     1,
			     intf->altsetting[0].desc.bInterfaceNumber,
			     intf->cur_altsetting->desc.bInterfaceNumber,
			     dconf,
			     sizeof(*dconf),
			     1000);
+1 −1
Original line number Diff line number Diff line
@@ -1590,7 +1590,7 @@ static int kvaser_usb_hydra_setup_endpoints(struct kvaser_usb *dev)
	struct usb_endpoint_descriptor *ep;
	int i;

	iface_desc = &dev->intf->altsetting[0];
	iface_desc = dev->intf->cur_altsetting;

	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		ep = &iface_desc->endpoint[i].desc;
+1 −1
Original line number Diff line number Diff line
@@ -1310,7 +1310,7 @@ static int kvaser_usb_leaf_setup_endpoints(struct kvaser_usb *dev)
	struct usb_endpoint_descriptor *endpoint;
	int i;

	iface_desc = &dev->intf->altsetting[0];
	iface_desc = dev->intf->cur_altsetting;

	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
		endpoint = &iface_desc->endpoint[i].desc;
Loading