drivers/net/mdio/mdio-gpio.c

Source file repositories/reference/linux-study-clean/drivers/net/mdio/mdio-gpio.c

File Facts

System
Linux kernel
Corpus path
drivers/net/mdio/mdio-gpio.c
Extension
.c
Size
5195 bytes
Lines
219
Domain
Driver Families
Bucket
drivers/net
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct mdio_gpio_info {
	struct mdiobb_ctrl ctrl;
	struct gpio_desc *mdc, *mdio, *mdo;
};

static int mdio_gpio_get_data(struct device *dev,
			      struct mdio_gpio_info *bitbang)
{
	bitbang->mdc = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDC,
					    GPIOD_OUT_LOW);
	if (IS_ERR(bitbang->mdc))
		return PTR_ERR(bitbang->mdc);

	bitbang->mdio = devm_gpiod_get_index(dev, NULL, MDIO_GPIO_MDIO,
					     GPIOD_IN);
	if (IS_ERR(bitbang->mdio))
		return PTR_ERR(bitbang->mdio);

	bitbang->mdo = devm_gpiod_get_index_optional(dev, NULL, MDIO_GPIO_MDO,
						     GPIOD_OUT_LOW);
	return PTR_ERR_OR_ZERO(bitbang->mdo);
}

static void mdio_dir(struct mdiobb_ctrl *ctrl, int dir)
{
	struct mdio_gpio_info *bitbang =
		container_of(ctrl, struct mdio_gpio_info, ctrl);

	if (bitbang->mdo) {
		/* Separate output pin. Always set its value to high
		 * when changing direction. If direction is input,
		 * assume the pin serves as pull-up. If direction is
		 * output, the default value is high.
		 */
		gpiod_set_value_cansleep(bitbang->mdo, 1);
		return;
	}

	if (dir)
		gpiod_direction_output(bitbang->mdio, 1);
	else
		gpiod_direction_input(bitbang->mdio);
}

static int mdio_get(struct mdiobb_ctrl *ctrl)
{
	struct mdio_gpio_info *bitbang =
		container_of(ctrl, struct mdio_gpio_info, ctrl);

	return gpiod_get_value_cansleep(bitbang->mdio);
}

static void mdio_set(struct mdiobb_ctrl *ctrl, int what)
{
	struct mdio_gpio_info *bitbang =
		container_of(ctrl, struct mdio_gpio_info, ctrl);

	if (bitbang->mdo)
		gpiod_set_value_cansleep(bitbang->mdo, what);
	else
		gpiod_set_value_cansleep(bitbang->mdio, what);
}

static void mdc_set(struct mdiobb_ctrl *ctrl, int what)
{
	struct mdio_gpio_info *bitbang =
		container_of(ctrl, struct mdio_gpio_info, ctrl);

	gpiod_set_value_cansleep(bitbang->mdc, what);
}

static const struct mdiobb_ops mdio_gpio_ops = {
	.owner = THIS_MODULE,
	.set_mdc = mdc_set,
	.set_mdio_dir = mdio_dir,
	.set_mdio_data = mdio_set,
	.get_mdio_data = mdio_get,
};

static struct mii_bus *mdio_gpio_bus_init(struct device *dev,
					  struct mdio_gpio_info *bitbang,
					  int bus_id)
{
	struct mii_bus *new_bus;

	bitbang->ctrl.ops = &mdio_gpio_ops;

	new_bus = alloc_mdio_bitbang(&bitbang->ctrl);
	if (!new_bus)
		return NULL;

Annotation

Implementation Notes