Commit ae189ccb authored by Jakub Kicinski's avatar Jakub Kicinski

Merge branch 'dsa-add-mt7530-gpio-support'

DENG Qingfang says:

====================
dsa: add MT7530 GPIO support

MT7530's LED controller can be used as GPIO controller.
Add support for it.
====================

Link: https://lore.kernel.org/r/20210125044322.6280-1-dqfext@gmail.comSigned-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 4fd59792 429a0ede
...@@ -76,6 +76,12 @@ phy-mode must be set, see also example 2 below! ...@@ -76,6 +76,12 @@ phy-mode must be set, see also example 2 below!
* mt7621: phy-mode = "rgmii-txid"; * mt7621: phy-mode = "rgmii-txid";
* mt7623: phy-mode = "rgmii"; * mt7623: phy-mode = "rgmii";
Optional properties:
- gpio-controller: Boolean; if defined, MT7530's LED controller will run on
GPIO mode.
- #gpio-cells: Must be 2 if gpio-controller is defined.
See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional See Documentation/devicetree/bindings/net/dsa/dsa.txt for a list of additional
required, optional properties and how the integrated switch subnodes must required, optional properties and how the integrated switch subnodes must
be specified. be specified.
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/regulator/consumer.h> #include <linux/regulator/consumer.h>
#include <linux/reset.h> #include <linux/reset.h>
#include <linux/gpio/consumer.h> #include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <net/dsa.h> #include <net/dsa.h>
#include "mt7530.h" #include "mt7530.h"
...@@ -1622,6 +1623,109 @@ mtk_get_tag_protocol(struct dsa_switch *ds, int port, ...@@ -1622,6 +1623,109 @@ mtk_get_tag_protocol(struct dsa_switch *ds, int port,
} }
} }
static inline u32
mt7530_gpio_to_bit(unsigned int offset)
{
/* Map GPIO offset to register bit
* [ 2: 0] port 0 LED 0..2 as GPIO 0..2
* [ 6: 4] port 1 LED 0..2 as GPIO 3..5
* [10: 8] port 2 LED 0..2 as GPIO 6..8
* [14:12] port 3 LED 0..2 as GPIO 9..11
* [18:16] port 4 LED 0..2 as GPIO 12..14
*/
return BIT(offset + offset / 3);
}
static int
mt7530_gpio_get(struct gpio_chip *gc, unsigned int offset)
{
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
return !!(mt7530_read(priv, MT7530_LED_GPIO_DATA) & bit);
}
static void
mt7530_gpio_set(struct gpio_chip *gc, unsigned int offset, int value)
{
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
if (value)
mt7530_set(priv, MT7530_LED_GPIO_DATA, bit);
else
mt7530_clear(priv, MT7530_LED_GPIO_DATA, bit);
}
static int
mt7530_gpio_get_direction(struct gpio_chip *gc, unsigned int offset)
{
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
return (mt7530_read(priv, MT7530_LED_GPIO_DIR) & bit) ?
GPIO_LINE_DIRECTION_OUT : GPIO_LINE_DIRECTION_IN;
}
static int
mt7530_gpio_direction_input(struct gpio_chip *gc, unsigned int offset)
{
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
mt7530_clear(priv, MT7530_LED_GPIO_OE, bit);
mt7530_clear(priv, MT7530_LED_GPIO_DIR, bit);
return 0;
}
static int
mt7530_gpio_direction_output(struct gpio_chip *gc, unsigned int offset, int value)
{
struct mt7530_priv *priv = gpiochip_get_data(gc);
u32 bit = mt7530_gpio_to_bit(offset);
mt7530_set(priv, MT7530_LED_GPIO_DIR, bit);
if (value)
mt7530_set(priv, MT7530_LED_GPIO_DATA, bit);
else
mt7530_clear(priv, MT7530_LED_GPIO_DATA, bit);
mt7530_set(priv, MT7530_LED_GPIO_OE, bit);
return 0;
}
static int
mt7530_setup_gpio(struct mt7530_priv *priv)
{
struct device *dev = priv->dev;
struct gpio_chip *gc;
gc = devm_kzalloc(dev, sizeof(*gc), GFP_KERNEL);
if (!gc)
return -ENOMEM;
mt7530_write(priv, MT7530_LED_GPIO_OE, 0);
mt7530_write(priv, MT7530_LED_GPIO_DIR, 0);
mt7530_write(priv, MT7530_LED_IO_MODE, 0);
gc->label = "mt7530";
gc->parent = dev;
gc->owner = THIS_MODULE;
gc->get_direction = mt7530_gpio_get_direction;
gc->direction_input = mt7530_gpio_direction_input;
gc->direction_output = mt7530_gpio_direction_output;
gc->get = mt7530_gpio_get;
gc->set = mt7530_gpio_set;
gc->base = -1;
gc->ngpio = 15;
gc->can_sleep = true;
return devm_gpiochip_add_data(dev, gc, priv);
}
static int static int
mt7530_setup(struct dsa_switch *ds) mt7530_setup(struct dsa_switch *ds)
{ {
...@@ -1763,6 +1867,12 @@ mt7530_setup(struct dsa_switch *ds) ...@@ -1763,6 +1867,12 @@ mt7530_setup(struct dsa_switch *ds)
} }
} }
if (of_property_read_bool(priv->dev->of_node, "gpio-controller")) {
ret = mt7530_setup_gpio(priv);
if (ret)
return ret;
}
mt7530_setup_port5(ds, interface); mt7530_setup_port5(ds, interface);
/* Flush the FDB table */ /* Flush the FDB table */
......
...@@ -554,6 +554,26 @@ enum mt7531_clk_skew { ...@@ -554,6 +554,26 @@ enum mt7531_clk_skew {
#define MT7531_GPIO12_RG_RXD3_MASK GENMASK(19, 16) #define MT7531_GPIO12_RG_RXD3_MASK GENMASK(19, 16)
#define MT7531_EXT_P_MDIO_12 (2 << 16) #define MT7531_EXT_P_MDIO_12 (2 << 16)
/* Registers for LED GPIO control (MT7530 only)
* All registers follow this pattern:
* [ 2: 0] port 0
* [ 6: 4] port 1
* [10: 8] port 2
* [14:12] port 3
* [18:16] port 4
*/
/* LED enable, 0: Disable, 1: Enable (Default) */
#define MT7530_LED_EN 0x7d00
/* LED mode, 0: GPIO mode, 1: PHY mode (Default) */
#define MT7530_LED_IO_MODE 0x7d04
/* GPIO direction, 0: Input, 1: Output */
#define MT7530_LED_GPIO_DIR 0x7d10
/* GPIO output enable, 0: Disable, 1: Enable */
#define MT7530_LED_GPIO_OE 0x7d14
/* GPIO value, 0: Low, 1: High */
#define MT7530_LED_GPIO_DATA 0x7d18
#define MT7530_CREV 0x7ffc #define MT7530_CREV 0x7ffc
#define CHIP_NAME_SHIFT 16 #define CHIP_NAME_SHIFT 16
#define MT7530_ID 0x7530 #define MT7530_ID 0x7530
......
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