162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2006 Juergen Beisert, Pengutronix
462306a36Sopenharmony_ci * Copyright (C) 2008 Guennadi Liakhovetski, Pengutronix
562306a36Sopenharmony_ci * Copyright (C) 2009 Wolfram Sang, Pengutronix
662306a36Sopenharmony_ci *
762306a36Sopenharmony_ci * Check max730x.c for further details.
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/init.h>
1262306a36Sopenharmony_ci#include <linux/platform_device.h>
1362306a36Sopenharmony_ci#include <linux/mutex.h>
1462306a36Sopenharmony_ci#include <linux/slab.h>
1562306a36Sopenharmony_ci#include <linux/spi/spi.h>
1662306a36Sopenharmony_ci#include <linux/spi/max7301.h>
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ci/* A write to the MAX7301 means one message with one transfer */
1962306a36Sopenharmony_cistatic int max7301_spi_write(struct device *dev, unsigned int reg,
2062306a36Sopenharmony_ci				unsigned int val)
2162306a36Sopenharmony_ci{
2262306a36Sopenharmony_ci	struct spi_device *spi = to_spi_device(dev);
2362306a36Sopenharmony_ci	u16 word = ((reg & 0x7F) << 8) | (val & 0xFF);
2462306a36Sopenharmony_ci
2562306a36Sopenharmony_ci	return spi_write_then_read(spi, &word, sizeof(word), NULL, 0);
2662306a36Sopenharmony_ci}
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_ci/* A read from the MAX7301 means two transfers; here, one message each */
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_cistatic int max7301_spi_read(struct device *dev, unsigned int reg)
3162306a36Sopenharmony_ci{
3262306a36Sopenharmony_ci	int ret;
3362306a36Sopenharmony_ci	u16 word;
3462306a36Sopenharmony_ci	struct spi_device *spi = to_spi_device(dev);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	word = 0x8000 | (reg << 8);
3762306a36Sopenharmony_ci	ret = spi_write_then_read(spi, &word, sizeof(word), &word,
3862306a36Sopenharmony_ci				  sizeof(word));
3962306a36Sopenharmony_ci	if (ret)
4062306a36Sopenharmony_ci		return ret;
4162306a36Sopenharmony_ci	return word & 0xff;
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic int max7301_probe(struct spi_device *spi)
4562306a36Sopenharmony_ci{
4662306a36Sopenharmony_ci	struct max7301 *ts;
4762306a36Sopenharmony_ci	int ret;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/* bits_per_word cannot be configured in platform data */
5062306a36Sopenharmony_ci	spi->bits_per_word = 16;
5162306a36Sopenharmony_ci	ret = spi_setup(spi);
5262306a36Sopenharmony_ci	if (ret < 0)
5362306a36Sopenharmony_ci		return ret;
5462306a36Sopenharmony_ci
5562306a36Sopenharmony_ci	ts = devm_kzalloc(&spi->dev, sizeof(struct max7301), GFP_KERNEL);
5662306a36Sopenharmony_ci	if (!ts)
5762306a36Sopenharmony_ci		return -ENOMEM;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	ts->read = max7301_spi_read;
6062306a36Sopenharmony_ci	ts->write = max7301_spi_write;
6162306a36Sopenharmony_ci	ts->dev = &spi->dev;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	ret = __max730x_probe(ts);
6462306a36Sopenharmony_ci	return ret;
6562306a36Sopenharmony_ci}
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistatic void max7301_remove(struct spi_device *spi)
6862306a36Sopenharmony_ci{
6962306a36Sopenharmony_ci	__max730x_remove(&spi->dev);
7062306a36Sopenharmony_ci}
7162306a36Sopenharmony_ci
7262306a36Sopenharmony_cistatic const struct spi_device_id max7301_id[] = {
7362306a36Sopenharmony_ci	{ "max7301", 0 },
7462306a36Sopenharmony_ci	{ }
7562306a36Sopenharmony_ci};
7662306a36Sopenharmony_ciMODULE_DEVICE_TABLE(spi, max7301_id);
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_cistatic struct spi_driver max7301_driver = {
7962306a36Sopenharmony_ci	.driver = {
8062306a36Sopenharmony_ci		.name = "max7301",
8162306a36Sopenharmony_ci	},
8262306a36Sopenharmony_ci	.probe = max7301_probe,
8362306a36Sopenharmony_ci	.remove = max7301_remove,
8462306a36Sopenharmony_ci	.id_table = max7301_id,
8562306a36Sopenharmony_ci};
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_cistatic int __init max7301_init(void)
8862306a36Sopenharmony_ci{
8962306a36Sopenharmony_ci	return spi_register_driver(&max7301_driver);
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci/* register after spi postcore initcall and before
9262306a36Sopenharmony_ci * subsys initcalls that may rely on these GPIOs
9362306a36Sopenharmony_ci */
9462306a36Sopenharmony_cisubsys_initcall(max7301_init);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic void __exit max7301_exit(void)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	spi_unregister_driver(&max7301_driver);
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_cimodule_exit(max7301_exit);
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ciMODULE_AUTHOR("Juergen Beisert, Wolfram Sang");
10362306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
10462306a36Sopenharmony_ciMODULE_DESCRIPTION("MAX7301 GPIO-Expander");
105