drivers/mfd/upboard-fpga.c

Source file repositories/reference/linux-study-clean/drivers/mfd/upboard-fpga.c

File Facts

System
Linux kernel
Corpus path
drivers/mfd/upboard-fpga.c
Extension
.c
Size
9931 bytes
Lines
325
Domain
Driver Families
Bucket
drivers/mfd
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

// SPDX-License-Identifier: GPL-2.0-only
/*
 * UP Board FPGA driver.
 *
 * FPGA provides more GPIO driving power, LEDS and pin mux function.
 *
 * Copyright (c) AAEON. All rights reserved.
 * Copyright (C) 2024 Bootlin
 *
 * Author: Gary Wang <garywang@aaeon.com.tw>
 * Author: Thomas Richard <thomas.richard@bootlin.com>
 */

#include <linux/bitfield.h>
#include <linux/device.h>
#include <linux/err.h>
#include <linux/gpio/consumer.h>
#include <linux/mfd/core.h>
#include <linux/mfd/upboard-fpga.h>
#include <linux/module.h>
#include <linux/mod_devicetable.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#include <linux/sysfs.h>

#define UPBOARD_AAEON_MANUFACTURER_ID	0x01
#define UPBOARD_MANUFACTURER_ID_MASK	GENMASK(7, 0)

#define UPBOARD_ADDRESS_SIZE  7
#define UPBOARD_REGISTER_SIZE 16

#define UPBOARD_READ_FLAG     BIT(UPBOARD_ADDRESS_SIZE)

#define UPBOARD_FW_ID_MAJOR_SUPPORTED	0x0

#define UPBOARD_FW_ID_BUILD_MASK	GENMASK(15, 12)
#define UPBOARD_FW_ID_MAJOR_MASK	GENMASK(11, 8)
#define UPBOARD_FW_ID_MINOR_MASK	GENMASK(7, 4)
#define UPBOARD_FW_ID_PATCH_MASK	GENMASK(3, 0)

static int upboard_fpga_read(void *context, unsigned int reg, unsigned int *val)
{
	struct upboard_fpga *fpga = context;
	int i;

	/* Clear to start new transaction */
	gpiod_set_value(fpga->clear_gpio, 0);
	gpiod_set_value(fpga->clear_gpio, 1);

	reg |= UPBOARD_READ_FLAG;

	/* Send clock and addr from strobe & datain pins */
	for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) {
		gpiod_set_value(fpga->strobe_gpio, 0);
		gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i)));
		gpiod_set_value(fpga->strobe_gpio, 1);
	}

	gpiod_set_value(fpga->strobe_gpio, 0);
	*val = 0;

	/* Read data from dataout pin */
	for (i = UPBOARD_REGISTER_SIZE - 1; i >= 0; i--) {
		gpiod_set_value(fpga->strobe_gpio, 1);
		gpiod_set_value(fpga->strobe_gpio, 0);
		*val |= gpiod_get_value(fpga->dataout_gpio) << i;
	}

	gpiod_set_value(fpga->strobe_gpio, 1);

	return 0;
}

static int upboard_fpga_write(void *context, unsigned int reg, unsigned int val)
{
	struct upboard_fpga *fpga = context;
	int i;

	/* Clear to start new transcation */
	gpiod_set_value(fpga->clear_gpio, 0);
	gpiod_set_value(fpga->clear_gpio, 1);

	/* Send clock and addr from strobe & datain pins */
	for (i = UPBOARD_ADDRESS_SIZE; i >= 0; i--) {
		gpiod_set_value(fpga->strobe_gpio, 0);
		gpiod_set_value(fpga->datain_gpio, !!(reg & BIT(i)));
		gpiod_set_value(fpga->strobe_gpio, 1);
	}

Annotation

Implementation Notes