Message ID | 20210816114840.17502-1-o.rempel@pengutronix.de |
---|---|
State | Superseded, archived |
Headers | show |
Series | [v1,1/3] dt-bindings: can-controller: add support for termination-gpios | expand |
Context | Check | Description |
---|---|---|
robh/checkpatch | success | |
robh/dt-meta-schema | success | |
robh/dtbs-check | success |
On Mon. 16 Aug 2021 at 20:48, Oleksij Rempel <o.rempel@pengutronix.de> wrote: > For CAN buses to work, a termination resistor has to be present at both > ends of the bus. This resistor is usually 120 Ohms, other values may be > required for special bus topologies. > > This patch adds support for a generic GPIO based CAN termination. The > resistor value has to be specified via device tree, and it can only be > attached to or detached from the bus. By default the termination is not > active. > > Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> > --- > drivers/net/can/dev/dev.c | 54 +++++++++++++++++++++++++++++++++++++++ > include/linux/can/dev.h | 7 +++++ > 2 files changed, 61 insertions(+) > > diff --git a/drivers/net/can/dev/dev.c b/drivers/net/can/dev/dev.c > index 311d8564d611..b4a6c7a6fc18 100644 > --- a/drivers/net/can/dev/dev.c > +++ b/drivers/net/can/dev/dev.c > @@ -15,6 +15,7 @@ > #include <linux/can/dev.h> > #include <linux/can/skb.h> > #include <linux/can/led.h> > +#include <linux/gpio/consumer.h> > #include <linux/of.h> > > #define MOD_DESC "CAN device driver interface" > @@ -400,10 +401,57 @@ void close_candev(struct net_device *dev) > } > EXPORT_SYMBOL_GPL(close_candev); > > +static int can_set_termination(struct net_device *ndev, u16 term) > +{ > + struct can_priv *priv = netdev_priv(ndev); > + int set; > + > + if (term == priv->termination_gpio_ohms[CAN_TERMINATION_GPIO_ENABLED]) > + set = 1; > + else > + set = 0; > + > + gpiod_set_value(priv->termination_gpio, set); > + > + return 0; > +} > + > +static int can_get_termination(struct net_device *ndev) > +{ > + struct can_priv *priv = netdev_priv(ndev); > + struct device *dev = ndev->dev.parent; > + struct gpio_desc *gpio; > + u16 term; > + int ret; > + > + /* Disabling termination by default is the safe choice: Else if many > + * bus participants enable it, no communication is possible at all. > + */ > + gpio = devm_gpiod_get_optional(dev, "termination", GPIOD_OUT_LOW); > + if (IS_ERR(gpio)) > + return dev_err_probe(dev, PTR_ERR(gpio), > + "Cannot get termination-gpios\n"); > + > + ret = device_property_read_u16(dev, "termination-ohms", &term); > + if (ret) > + return ret; > + > + priv->termination_const_cnt = ARRAY_SIZE(priv->termination_gpio_ohms); > + priv->termination_const = priv->termination_gpio_ohms; > + priv->termination_gpio = gpio; > + priv->termination_gpio_ohms[CAN_TERMINATION_GPIO_DISABLED] = > + CAN_TERMINATION_DISABLED; > + priv->termination_gpio_ohms[CAN_TERMINATION_GPIO_ENABLED] = term; > + priv->do_set_termination = can_set_termination; > + > + return 0; > +} > + > /* Register the CAN network device */ > int register_candev(struct net_device *dev) > { > struct can_priv *priv = netdev_priv(dev); > + int err; > > /* Ensure termination_const, termination_const_cnt and > * do_set_termination consistency. All must be either set or > @@ -419,6 +467,12 @@ int register_candev(struct net_device *dev) > if (!priv->data_bitrate_const != !priv->data_bitrate_const_cnt) > return -EINVAL; > > + if (!priv->termination_const) { > + err = can_get_termination(dev); > + if (err) > + return err; > + } > + > dev->rtnl_link_ops = &can_link_ops; > netif_carrier_off(dev); > > diff --git a/include/linux/can/dev.h b/include/linux/can/dev.h > index 27b275e463da..82bdc5b09a3a 100644 > --- a/include/linux/can/dev.h > +++ b/include/linux/can/dev.h > @@ -32,6 +32,11 @@ enum can_mode { > CAN_MODE_SLEEP > }; > > +enum can_termination_gpio { > + CAN_TERMINATION_GPIO_DISABLED = 0, > + CAN_TERMINATION_GPIO_ENABLED, I would add a last entry to automatically calculate the length of the termination_gpio_ohms array. + CAN_TERMINATION_GPIO_MAX > +}; > + > /* > * CAN common private data > */ > @@ -55,6 +60,8 @@ struct can_priv { > unsigned int termination_const_cnt; > const u16 *termination_const; > u16 termination; > + struct gpio_desc *termination_gpio; > + u16 termination_gpio_ohms[2]; This way, you can replace the constant value 2: + u16 termination_gpio_ohms[CAN_TERMINATION_GPIO_MAX]; > > enum can_state state; Yours sincerely, Vincent
diff --git a/Documentation/devicetree/bindings/net/can/can-controller.yaml b/Documentation/devicetree/bindings/net/can/can-controller.yaml index 9cf2ae097156..298ce69a8208 100644 --- a/Documentation/devicetree/bindings/net/can/can-controller.yaml +++ b/Documentation/devicetree/bindings/net/can/can-controller.yaml @@ -13,6 +13,15 @@ properties: $nodename: pattern: "^can(@.*)?$" + termination-gpios: + description: GPIO pin to enable CAN bus termination. + + termination-ohms: + description: The resistance value of the CAN bus termination resistor. + $ref: /schemas/types.yaml#/definitions/uint16-array + minimum: 1 + maximum: 65535 + additionalProperties: true ...
Some boards provide GPIO controllable termination resistor. Provide binding to make use of it. Signed-off-by: Oleksij Rempel <o.rempel@pengutronix.de> --- .../devicetree/bindings/net/can/can-controller.yaml | 9 +++++++++ 1 file changed, 9 insertions(+)