brintos

brintos / linux-shallow public Read only

0
0
Text · 3.1 KiB · cb7e022 Raw
155 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (C) IBM Corporation 2023 */3 4#include <linux/cdev.h>5#include <linux/device.h>6#include <linux/fs.h>7#include <linux/fsi.h>8#include <linux/module.h>9#include <linux/mod_devicetable.h>10 11#include "fsi-master-i2cr.h"12#include "fsi-slave.h"13 14struct i2cr_scom {15	struct device dev;16	struct cdev cdev;17	struct fsi_master_i2cr *i2cr;18};19 20static loff_t i2cr_scom_llseek(struct file *file, loff_t offset, int whence)21{22	switch (whence) {23	case SEEK_CUR:24		break;25	case SEEK_SET:26		file->f_pos = offset;27		break;28	default:29		return -EINVAL;30	}31 32	return offset;33}34 35static ssize_t i2cr_scom_read(struct file *filep, char __user *buf, size_t len, loff_t *offset)36{37	struct i2cr_scom *scom = filep->private_data;38	u64 data;39	int ret;40 41	if (len != sizeof(data))42		return -EINVAL;43 44	ret = fsi_master_i2cr_read(scom->i2cr, (u32)*offset, &data);45	if (ret)46		return ret;47 48	ret = copy_to_user(buf, &data, len);49	if (ret)50		return ret;51 52	return len;53}54 55static ssize_t i2cr_scom_write(struct file *filep, const char __user *buf, size_t len,56			       loff_t *offset)57{58	struct i2cr_scom *scom = filep->private_data;59	u64 data;60	int ret;61 62	if (len != sizeof(data))63		return -EINVAL;64 65	ret = copy_from_user(&data, buf, len);66	if (ret)67		return ret;68 69	ret = fsi_master_i2cr_write(scom->i2cr, (u32)*offset, data);70	if (ret)71		return ret;72 73	return len;74}75 76static const struct file_operations i2cr_scom_fops = {77	.owner		= THIS_MODULE,78	.open		= simple_open,79	.llseek		= i2cr_scom_llseek,80	.read		= i2cr_scom_read,81	.write		= i2cr_scom_write,82};83 84static int i2cr_scom_probe(struct device *dev)85{86	struct fsi_device *fsi_dev = to_fsi_dev(dev);87	struct i2cr_scom *scom;88	int didx;89	int ret;90 91	if (!is_fsi_master_i2cr(fsi_dev->slave->master))92		return -ENODEV;93 94	scom = devm_kzalloc(dev, sizeof(*scom), GFP_KERNEL);95	if (!scom)96		return -ENOMEM;97 98	scom->i2cr = to_fsi_master_i2cr(fsi_dev->slave->master);99	dev_set_drvdata(dev, scom);100 101	scom->dev.type = &fsi_cdev_type;102	scom->dev.parent = dev;103	device_initialize(&scom->dev);104 105	ret = fsi_get_new_minor(fsi_dev, fsi_dev_scom, &scom->dev.devt, &didx);106	if (ret)107		return ret;108 109	dev_set_name(&scom->dev, "scom%d", didx);110	cdev_init(&scom->cdev, &i2cr_scom_fops);111	ret = cdev_device_add(&scom->cdev, &scom->dev);112	if (ret)113		fsi_free_minor(scom->dev.devt);114 115	return ret;116}117 118static int i2cr_scom_remove(struct device *dev)119{120	struct i2cr_scom *scom = dev_get_drvdata(dev);121 122	cdev_device_del(&scom->cdev, &scom->dev);123	fsi_free_minor(scom->dev.devt);124 125	return 0;126}127 128static const struct of_device_id i2cr_scom_of_ids[] = {129	{ .compatible = "ibm,i2cr-scom" },130	{ }131};132MODULE_DEVICE_TABLE(of, i2cr_scom_of_ids);133 134static const struct fsi_device_id i2cr_scom_ids[] = {135	{ 0x5, FSI_VERSION_ANY },136	{ }137};138 139static struct fsi_driver i2cr_scom_driver = {140	.id_table = i2cr_scom_ids,141	.drv = {142		.name = "i2cr_scom",143		.bus = &fsi_bus_type,144		.of_match_table = i2cr_scom_of_ids,145		.probe = i2cr_scom_probe,146		.remove = i2cr_scom_remove,147	}148};149 150module_fsi_driver(i2cr_scom_driver);151 152MODULE_AUTHOR("Eddie James <eajames@linux.ibm.com>");153MODULE_DESCRIPTION("IBM I2C Responder SCOM driver");154MODULE_LICENSE("GPL");155