drivers/soc/cirrus/soc-ep93xx.c

Source file repositories/reference/linux-study-clean/drivers/soc/cirrus/soc-ep93xx.c

File Facts

System
Linux kernel
Corpus path
drivers/soc/cirrus/soc-ep93xx.c
Extension
.c
Size
6845 bytes
Lines
253
Domain
Driver Families
Bucket
drivers/soc
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 ep93xx_map_info {
	spinlock_t lock;
	void __iomem *base;
	struct regmap *map;
};

/*
 * EP93xx System Controller software locked register write
 *
 * Logic safeguards are included to condition the control signals for
 * power connection to the matrix to prevent part damage. In addition, a
 * software lock register is included that must be written with 0xAA
 * before each register write to change the values of the four switch
 * matrix control registers.
 */
static void ep93xx_regmap_write(struct regmap *map, spinlock_t *lock,
				 unsigned int reg, unsigned int val)
{
	guard(spinlock_irqsave)(lock);

	regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
	regmap_write(map, reg, val);
}

static void ep93xx_regmap_update_bits(struct regmap *map, spinlock_t *lock,
				      unsigned int reg, unsigned int mask,
				      unsigned int val)
{
	guard(spinlock_irqsave)(lock);

	regmap_write(map, EP93XX_SYSCON_SWLOCK, EP93XX_SWLOCK_MAGICK);
	/* force write is required to clear swlock if no changes are made */
	regmap_update_bits_base(map, reg, mask, val, NULL, false, true);
}

static void ep93xx_unregister_adev(void *_adev)
{
	struct auxiliary_device *adev = _adev;

	auxiliary_device_delete(adev);
	auxiliary_device_uninit(adev);
}

static void ep93xx_adev_release(struct device *dev)
{
	struct auxiliary_device *adev = to_auxiliary_dev(dev);
	struct ep93xx_regmap_adev *rdev = to_ep93xx_regmap_adev(adev);

	kfree(rdev);
}

static struct auxiliary_device __init *ep93xx_adev_alloc(struct device *parent,
							 const char *name,
							 struct ep93xx_map_info *info)
{
	struct ep93xx_regmap_adev *rdev __free(kfree) = NULL;
	struct auxiliary_device *adev;
	int ret;

	rdev = kzalloc_obj(*rdev);
	if (!rdev)
		return ERR_PTR(-ENOMEM);

	rdev->map = info->map;
	rdev->base = info->base;
	rdev->lock = &info->lock;
	rdev->write = ep93xx_regmap_write;
	rdev->update_bits = ep93xx_regmap_update_bits;

	adev = &rdev->adev;
	adev->name = name;
	adev->dev.parent = parent;
	adev->dev.release = ep93xx_adev_release;

	ret = auxiliary_device_init(adev);
	if (ret)
		return ERR_PTR(ret);

	return &no_free_ptr(rdev)->adev;
}

static int __init ep93xx_controller_register(struct device *parent, const char *name,
					     struct ep93xx_map_info *info)
{
	struct auxiliary_device *adev;
	int ret;

	adev = ep93xx_adev_alloc(parent, name, info);
	if (IS_ERR(adev))
		return PTR_ERR(adev);

Annotation

Implementation Notes