// SPDX-License-Identifier: GPL-2.0-only
#include <linux/array_size.h>
#include <linux/bitfield.h>
#include <linux/bits.h>
#include <linux/dev_printk.h>
#include <linux/device.h>
#include <linux/export.h>
#include <linux/math64.h>
#include <linux/module.h>
#include <linux/netlink.h>
#include <linux/regmap.h>
#include <linux/sprintf.h>
#include <linux/string_choices.h>
#include <linux/unaligned.h>
#include <net/devlink.h>
#include "core.h"
#include "devlink.h"
#include "dpll.h"
#include "regs.h"
#define ZL_CHIP_INFO(_id, _nchannels, _flags) \
{ .id = (_id), .num_channels = (_nchannels), .flags = (_flags) }
static const struct zl3073x_chip_info zl3073x_chip_ids[] = {
ZL_CHIP_INFO(0x0E30, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E93, 1, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E94, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E95, 3, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E96, 4, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x0E97, 5, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x1E93, 1, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1E94, 2, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1E95, 3, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1E96, 4, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1E97, 5, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x1F60, 2, ZL3073X_FLAG_REF_PHASE_COMP_32),
ZL_CHIP_INFO(0x2E93, 1, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x2E94, 2, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x2E95, 3, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x2E96, 4, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x2E97, 5, ZL3073X_FLAG_DIE_TEMP),
ZL_CHIP_INFO(0x3FC4, 2, ZL3073X_FLAG_DIE_TEMP),
};
#define ZL_RANGE_OFFSET 0x80
#define ZL_PAGE_SIZE 0x80
#define ZL_NUM_PAGES 256
#define ZL_PAGE_SEL 0x7F
#define ZL_PAGE_SEL_MASK GENMASK(7, 0)
#define ZL_NUM_REGS (ZL_NUM_PAGES * ZL_PAGE_SIZE)
/* Regmap range configuration */
static const struct regmap_range_cfg zl3073x_regmap_range = {
.range_min = ZL_RANGE_OFFSET,
.range_max = ZL_RANGE_OFFSET + ZL_NUM_REGS - 1,
.selector_reg = ZL_PAGE_SEL,
.selector_mask = ZL_PAGE_SEL_MASK,
.selector_shift = 0,
.window_start = 0,
.window_len = ZL_PAGE_SIZE,
};
static bool
zl3073x_is_volatile_reg(struct device *dev __maybe_unused, unsigned int reg)
{
/* Only page selector is non-volatile */
return reg != ZL_PAGE_SEL;
}
const struct regmap_config zl3073x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
.max_register = ZL_RANGE_OFFSET + ZL_NUM_REGS - 1,
.ranges = &zl3073x_regmap_range,
.num_ranges = 1,
.cache_type = REGCACHE_MAPLE,
.volatile_reg = zl3073x_is_volatile_reg,
};
EXPORT_SYMBOL_NS_GPL(zl3073x_regmap_config, "ZL3073X");
static bool
zl3073x_check_reg(struct zl3073x_dev *zldev, unsigned int reg, size_t size)
{
/* Check that multiop lock is held when accessing registers
* from page 10 and above except the page 255 that does not
* need this protection.
*/
if (ZL_REG_PAGE(reg) >= 10 && ZL_REG_PAGE(reg) < 255)
lockdep_assert_held(&zldev->multiop_lock);
/* Check the index is in valid range for indexed register */
if (ZL_REG_OFFSET(reg) > ZL_REG_MAX_OFFSET(reg)) {
dev_err(zldev->dev, "Index out of range for reg 0x%04lx\n",
ZL_REG_ADDR(reg));
return false;
}
/* Check the requested size corresponds to register size */
if (ZL_REG_SIZE(reg) != size) {
dev_err(zldev->dev, "Invalid size %zu for reg 0x%04lx\n",
size, ZL_REG_ADDR(reg));
return false;
}
return true;
}
static <