File Index
Files and directories
Sign in
FILE

max77759-nvmem.c

File preview with syntax highlighting.

linux-6.19.14/drivers/nvmem/max77759-nvmem.c C
  1// SPDX-License-Identifier: GPL-2.0-only
  2//
  3// Copyright 2020 Google Inc
  4// Copyright 2025 Linaro Ltd.
  5//
  6// NVMEM driver for Maxim MAX77759
  7
  8#include <linux/dev_printk.h>
  9#include <linux/device.h>
 10#include <linux/device/driver.h>
 11#include <linux/err.h>
 12#include <linux/mfd/max77759.h>
 13#include <linux/mod_devicetable.h>
 14#include <linux/module.h>
 15#include <linux/nvmem-provider.h>
 16#include <linux/overflow.h>
 17#include <linux/platform_device.h>
 18#include <linux/string.h>
 19
 20#define MAX77759_NVMEM_OPCODE_HEADER_LEN 3
 21/*
 22 * NVMEM commands have a three byte header (which becomes part of the command),
 23 * so we need to subtract that.
 24 */
 25#define MAX77759_NVMEM_SIZE (MAX77759_MAXQ_OPCODE_MAXLENGTH \
 26			     - MAX77759_NVMEM_OPCODE_HEADER_LEN)
 27
 28struct max77759_nvmem {
 29	struct device *dev;
 30	struct max77759 *max77759;
 31};
 32
 33static int max77759_nvmem_reg_read(void *priv, unsigned int offset,
 34				   void *val, size_t bytes)
 35{
 36	struct max77759_nvmem *nvmem = priv;
 37	DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length,
 38		    MAX77759_NVMEM_OPCODE_HEADER_LEN);
 39	DEFINE_FLEX(struct max77759_maxq_response, rsp, rsp, length,
 40		    MAX77759_MAXQ_OPCODE_MAXLENGTH);
 41	int ret;
 42
 43	cmd->cmd[0] = MAX77759_MAXQ_OPCODE_USER_SPACE_READ;
 44	cmd->cmd[1] = offset;
 45	cmd->cmd[2] = bytes;
 46	rsp->length = bytes + MAX77759_NVMEM_OPCODE_HEADER_LEN;
 47
 48	ret = max77759_maxq_command(nvmem->max77759, cmd, rsp);
 49	if (ret < 0)
 50		return ret;
 51
 52	if (memcmp(cmd->cmd, rsp->rsp, MAX77759_NVMEM_OPCODE_HEADER_LEN)) {
 53		dev_warn(nvmem->dev, "protocol error (read)\n");
 54		return -EIO;
 55	}
 56
 57	memcpy(val, &rsp->rsp[MAX77759_NVMEM_OPCODE_HEADER_LEN], bytes);
 58
 59	return 0;
 60}
 61
 62static int max77759_nvmem_reg_write(void *priv, unsigned int offset,
 63				    void *val, size_t bytes)
 64{
 65	struct max77759_nvmem *nvmem = priv;
 66	DEFINE_FLEX(struct max77759_maxq_command, cmd, cmd, length,
 67		    MAX77759_MAXQ_OPCODE_MAXLENGTH);
 68	DEFINE_FLEX(struct max77759_maxq_response, rsp, rsp, length,
 69		    MAX77759_MAXQ_OPCODE_MAXLENGTH);
 70	int ret;
 71
 72	cmd->cmd[0] = MAX77759_MAXQ_OPCODE_USER_SPACE_WRITE;
 73	cmd->cmd[1] = offset;
 74	cmd->cmd[2] = bytes;
 75	memcpy(&cmd->cmd[MAX77759_NVMEM_OPCODE_HEADER_LEN], val, bytes);
 76	cmd->length = bytes + MAX77759_NVMEM_OPCODE_HEADER_LEN;
 77	rsp->length = cmd->length;
 78
 79	ret = max77759_maxq_command(nvmem->max77759, cmd, rsp);
 80	if (ret < 0)
 81		return ret;
 82
 83	if (memcmp(cmd->cmd, rsp->rsp, cmd->length)) {
 84		dev_warn(nvmem->dev, "protocol error (write)\n");
 85		return -EIO;
 86	}
 87
 88	return 0;
 89}
 90
 91static int max77759_nvmem_probe(struct platform_device *pdev)
 92{
 93	struct nvmem_config config = {
 94		.dev = &pdev->dev,
 95		.name = dev_name(&pdev->dev),
 96		.id = NVMEM_DEVID_NONE,
 97		.type = NVMEM_TYPE_EEPROM,
 98		.ignore_wp = true,
 99		.size = MAX77759_NVMEM_SIZE,
100		.word_size = sizeof(u8),
101		.stride = sizeof(u8),
102		.reg_read = max77759_nvmem_reg_read,
103		.reg_write = max77759_nvmem_reg_write,
104	};
105	struct max77759_nvmem *nvmem;
106
107	nvmem = devm_kzalloc(&pdev->dev, sizeof(*nvmem), GFP_KERNEL);
108	if (!nvmem)
109		return -ENOMEM;
110
111	nvmem->dev = &pdev->dev;
112	nvmem->max77759 = dev_get_drvdata(pdev->dev.parent);
113
114	config.priv = nvmem;
115
116	return PTR_ERR_OR_ZERO(devm_nvmem_register(config.dev, &config));
117}
118
119static const struct of_device_id max77759_nvmem_of_id[] = {
120	{ .compatible = "maxim,max77759-nvmem", },
121	{ }
122};
123MODULE_DEVICE_TABLE(of, max77759_nvmem_of_id);
124
125static const struct platform_device_id max77759_nvmem_platform_id[] = {
126	{ "max77759-nvmem", },
127	{ }
128};
129MODULE_DEVICE_TABLE(platform, max77759_nvmem_platform_id);
130
131static struct platform_driver max77759_nvmem_driver = {
132	.driver = {
133		.name = "max77759-nvmem",
134		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
135		.of_match_table = max77759_nvmem_of_id,
136	},
137	.probe = max77759_nvmem_probe,
138	.id_table = max77759_nvmem_platform_id,
139};
140
141module_platform_driver(max77759_nvmem_driver);
142
143MODULE_AUTHOR("André Draszik <andre.draszik@linaro.org>");
144MODULE_DESCRIPTION("NVMEM driver for Maxim MAX77759");
145MODULE_LICENSE("GPL");
~/ Read-only file preview.