firmware/br-ext-chip-allwinner/board/v83x/kernel/patches/00000-drivers_i2c_busses_i2...

380 lines
9.1 KiB
Diff

diff -drupN a/drivers/i2c/busses/i2c-sunxi-test.c b/drivers/i2c/busses/i2c-sunxi-test.c
--- a/drivers/i2c/busses/i2c-sunxi-test.c 1970-01-01 03:00:00.000000000 +0300
+++ b/drivers/i2c/busses/i2c-sunxi-test.c 2022-06-12 05:28:14.000000000 +0300
@@ -0,0 +1,375 @@
+/*
+ * at24.c - handle most I2C EEPROMs
+ *
+ * Copyright (C) 2005-2007 David Brownell
+ * Copyright (C) 2008 Wolfram Sang, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/mutex.h>
+#include <linux/sysfs.h>
+#include <linux/mod_devicetable.h>
+#include <linux/log2.h>
+#include <linux/bitops.h>
+#include <linux/jiffies.h>
+#include <linux/of.h>
+#include <linux/i2c.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/uaccess.h>
+#include <asm/io.h>
+#include <linux/i2c-dev.h>
+#include "i2c-sunxi.h"
+
+static u32 debug_mask = 1;
+#define dprintk(level_mask, fmt, arg...) \
+do { \
+ if (unlikely(debug_mask & level_mask)) \
+ pr_warn("%s()%d - "fmt, __func__, __LINE__, ##arg); \
+} while (0)
+
+#define I2C_ERR(fmt, arg...) pr_warn("%s()%d - "fmt, \
+ __func__, __LINE__, ##arg)
+#define EEPROM_NAME_SIZE 6
+#define I2C_TEST _IOR('i', 1, struct at24_data)
+
+struct at24_data {
+ unsigned short flags, num, len;
+ unsigned char command, value, *buf;
+};
+
+struct at24_dev {
+ struct device *dev;
+ struct cdev cdev;
+ dev_t chrdev;
+};
+
+static struct class *at24_class;
+static struct at24_dev *at24_dev;
+struct i2c_client *this_client;
+static __u32 twi_id;
+static const unsigned short i2c_address[] = {0x50, I2C_CLIENT_END};
+static const struct i2c_device_id at24_ids[] = {
+ { "24c16", 0 },
+ { /* END OF LIST */ }
+};
+MODULE_DEVICE_TABLE(i2c, at24_ids);
+
+/*
+ * at24_detect - Device detection callback for automatic device creation
+ * return value:
+ * = 0; success;
+ * < 0; err
+ */
+static int at24_detect(struct i2c_client *client, struct i2c_board_info *info)
+{
+ struct i2c_adapter *adapter = client->adapter;
+ struct device_node *np = NULL;
+
+ np = of_find_node_by_name(NULL, "at24c");
+ if (!np) {
+ I2C_ERR("get at24c para failed\n");
+ return -EINVAL;
+ }
+
+ if (!of_device_is_available(np)) {
+ I2C_ERR("at24c is not used\n");
+ return -EINVAL;
+ }
+
+ if (of_property_read_u32(np, "twi_id", &twi_id)) {
+ I2C_ERR("get at24c twi_id is failed\n");
+ return -EINVAL;
+ }
+
+ dprintk(DEBUG_INIT, "detecting\n");
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ I2C_ERR("function err\n");
+ return -ENODEV;
+ }
+ if (twi_id == adapter->nr) {
+ dprintk(DEBUG_INIT, "twi_id = %d\n", twi_id);
+ strlcpy(info->type, "24c16", EEPROM_NAME_SIZE);
+ }
+
+ return 0;
+}
+
+/*
+ * at24_ioctl -
+ * return value:
+ * = 0; success;
+ * < 0; err
+ */
+static long at24_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct i2c_client *client = file->private_data;
+ struct i2c_adapter *adapter = client->adapter;
+ struct at24_data *at24;
+ struct i2c_msg *msgs = NULL;
+ unsigned int size, i = 0;
+ unsigned char *buf = NULL;
+ int ret = 0;
+
+ at24 = kzalloc(sizeof(at24), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(at24)) {
+ I2C_ERR("kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ switch (cmd) {
+ case I2C_TEST:
+ size = _IOC_SIZE(cmd);
+ if (copy_from_user(at24, (void __user *)arg, size)) {
+ I2C_ERR("copy buffer err\n");
+ return -ENOMEM;
+ }
+
+ dprintk(DEBUG_INFO, "at24: flg = 0x%x, num = %d, len = %d\n",
+ at24->flags, at24->num, at24->len);
+ dprintk(DEBUG_INFO, " cmm = 0x%x, val = 0x%x\n",
+ at24->command, at24->value);
+
+ if (at24->num == 1) {
+ if (at24->flags == 1) {
+ /* 1 msgs read */
+ buf = kzalloc(sizeof(buf)*(at24->len),
+ GFP_KERNEL);
+ if (IS_ERR_OR_NULL(buf)) {
+ I2C_ERR("kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ ret = i2c_master_recv(client, buf, at24->len);
+ if (ret > 0)
+ ret = copy_to_user(at24->buf, buf,
+ at24->len) ? -EFAULT : 0;
+ } else if (at24->flags == 0) {
+ /* 1 msgs write */
+ buf = kzalloc(at24->len + 1, GFP_KERNEL);
+ if (IS_ERR_OR_NULL(buf)) {
+ I2C_ERR("kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ buf[0] = at24->command;
+ if (at24->len) {
+ for (i = 0; i < at24->len; i++)
+ buf[i + 1] = at24->value;
+ }
+ at24->len += 1;
+ i2c_master_send(client, buf, at24->len);
+ ret = 0;
+ } else {
+ I2C_ERR("err flags : 0x%x\n", at24->flags);
+ return -EINVAL;
+ }
+ kfree(buf);
+ } else if (at24->num == 2) {
+ /* 2 msgs read */
+ msgs = kzalloc(sizeof(msgs)*2, GFP_KERNEL);
+ buf = kzalloc(at24->len, GFP_KERNEL);
+ if (IS_ERR_OR_NULL(buf) || IS_ERR_OR_NULL(msgs)) {
+ I2C_ERR("kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ msgs[0].addr = client->addr;
+ msgs[0].len = 1;
+ msgs[0].buf = &(at24->command);
+ msgs[1].addr = client->addr;
+ msgs[1].flags |= I2C_M_RD,
+ msgs[1].len = at24->len;
+ msgs[1].buf = buf;
+
+ ret = i2c_transfer(adapter, msgs, at24->num);
+ if (ret < 0) {
+ kfree(buf);
+ kfree(msgs);
+ buf = NULL;
+ msgs = NULL;
+ return ret;
+ }
+
+ if (ret > 0)
+ ret = copy_to_user(at24->buf, buf, at24->len)
+ ? -EFAULT : 0;
+ kfree(buf);
+ kfree(msgs);
+ buf = NULL;
+ msgs = NULL;
+ } else {
+ /* n msgs write */
+ struct i2c_msg msgsa[at24->num];
+
+ for (i = 0; i < at24->num; i++) {
+ msgsa[i].addr = client->addr;
+ msgsa[i].len = 2;
+ msgsa[i].buf = kzalloc(msgsa[i].len, GFP_KERNEL);
+ if (IS_ERR_OR_NULL(msgsa[i].buf)) {
+ I2C_ERR("kzalloc failed\n");
+ return -ENOMEM;
+ }
+ msgsa[i].buf[0] = at24->command + i*2;
+ msgsa[i].buf[1] = at24->value;
+ msgsa[i].flags = 0;
+ }
+
+ ret = i2c_transfer(adapter, msgsa, at24->num);
+ for (i = 0; i < at24->num; i++) {
+ kfree(msgsa[i].buf);
+ msgsa[i].buf = NULL;
+ }
+ if (ret == at24->num)
+ ret = 0;
+ else
+ return ret;
+ }
+ break;
+ default:
+ I2C_ERR("ERR FORMAT\n");
+ return -ENOTTY;
+ }
+ kfree(at24);
+ return ret;
+}
+
+static int at24_open(struct inode *inode, struct file *file)
+{
+ dprintk(DEBUG_INFO, "open\n");
+
+ if (this_client)
+ file->private_data = this_client;
+ else {
+ I2C_ERR("no such dev\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int at24_release(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
+static const struct file_operations at24_fops = {
+ .owner = THIS_MODULE,
+ .llseek = no_llseek,
+ .unlocked_ioctl = at24_ioctl,
+ .open = at24_open,
+ .release = at24_release,
+};
+
+static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
+{
+ int err = 0;
+ struct device *dev;
+
+ this_client = client;
+
+ dprintk(DEBUG_INIT, "begin probe\n");
+
+ at24_dev = kzalloc(sizeof(struct at24_dev), GFP_KERNEL);
+ if (IS_ERR_OR_NULL(at24_dev)) {
+ I2C_ERR("kzalloc failed\n");
+ return -ENOMEM;
+ }
+
+ err = alloc_chrdev_region(&at24_dev->chrdev, 0, 1, "at24-dev");
+
+ if (err) {
+ I2C_ERR("alloc_chrdev_region failed\n");
+ goto alloc_chrdev_err;
+ }
+
+ cdev_init(&(at24_dev->cdev), &at24_fops);
+ at24_dev->cdev.owner = THIS_MODULE;
+ err = cdev_add(&(at24_dev->cdev), at24_dev->chrdev, 1);
+ if (err) {
+ I2C_ERR("cdev_add failed\n");
+ goto cdev_add_err;
+ }
+
+ at24_class = class_create(THIS_MODULE, "at24_char_class");
+ if (IS_ERR(at24_class)) {
+ err = PTR_ERR(at24_class);
+ I2C_ERR("class_create failed\n");
+ goto class_err;
+ }
+
+ dev = device_create(at24_class, NULL, at24_dev->chrdev, NULL,
+ "at24");
+ if (IS_ERR(dev)) {
+ err = PTR_ERR(dev);
+ I2C_ERR("device_create failed\n");
+ goto device_err;
+ }
+
+ dprintk(DEBUG_INIT, "ok\n");
+ return 0;
+
+device_err:
+ device_destroy(at24_class, at24_dev->chrdev);
+class_err:
+ cdev_del(&(at24_dev->cdev));
+cdev_add_err:
+ unregister_chrdev_region(at24_dev->chrdev, 1);
+alloc_chrdev_err:
+ kfree(at24_dev);
+
+ return err;
+}
+
+static int at24_remove(struct i2c_client *client)
+{
+ return 0;
+}
+
+/*-------------------------------------------------------------------------*/
+
+static struct i2c_driver at24_driver = {
+ .class = I2C_CLASS_SPD,
+ .driver = {
+ .name = "24c16",
+ .owner = THIS_MODULE,
+ },
+ .probe = at24_probe,
+ .remove = at24_remove,
+ .id_table = at24_ids,
+ .detect = at24_detect,
+ .address_list = i2c_address,
+};
+
+static int __init at24_init(void)
+{
+ dprintk(DEBUG_INIT, "begin init\n");
+ return i2c_add_driver(&at24_driver);
+
+}
+
+static void __exit at24_exit(void)
+{
+ cdev_del(&(at24_dev->cdev));
+ unregister_chrdev_region(at24_dev->chrdev, 1);
+ device_destroy(at24_class, at24_dev->chrdev);
+ class_destroy(at24_class);
+ kfree(at24_dev);
+ i2c_del_driver(&at24_driver);
+}
+
+module_init(at24_init);
+module_exit(at24_exit);
+module_param_named(debug, debug_mask, int, 0664);
+MODULE_DESCRIPTION("24C16 simple test");
+MODULE_AUTHOR("pannan");
+MODULE_LICENSE("GPL");