Files
android/drivers/misc/maxim/onewire_gpio.c
threeeye bc1d038eac REVVL 6 Pro kernel bring-up: full working tree snapshot (2026-09-12)
Squashed backup commit (no shallow-clone history issues) of
xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2 branch, upstream
commit 9eece662e) plus all fixes applied to get everpal_defconfig building
clean against a modern (GCC 15.2.0) toolchain -- see the previous commit
message on the lineage-23.2 branch (also in this repo history is not
available here since this is a squashed snapshot; full incremental history
lives in the local DL380 checkout and the upstream GitHub remote).

Upstream: https://github.com/xiaomi-mt6833-dev/kernel_xiaomi_mt6833 (lineage-23.2)
2026-09-12 13:36:46 +00:00

660 lines
17 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Copyright (c) 2016 xiaomi Inc.
*/
#define pr_fmt(fmt) "[Onewire] %s: " fmt, __func__
#include <linux/slab.h> /* kfree() */
#include <linux/module.h>
#include <linux/err.h>
#include <linux/gpio.h>
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/of_gpio.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/of.h>
#include <linux/io.h>
#include <linux/init.h>
#include <linux/gpio/driver.h>
#include <linux/gpio/consumer.h>
#include <linux/list.h>
#include <linux/device.h>
#include <linux/spinlock.h>
#define ow_info pr_info
#define ow_dbg pr_debug
#define ow_err pr_err
#define ow_log pr_err
/*
#define DRV_STRENGTH_16MA (0x7 << 6)
#define DRV_STRENGTH_4MA (0x1 << 6)
#define GPIO_OUTPUT (0x1 << 9)
#define GPIO_INPUT (0x0 << 9)
#define GPIO_PULL_UP 0x3
#define OUTPUT_HIGH (0x1 << 1)
#define OUTPUT_LOW 0x1
*/
#define ONE_WIRE_GPIO_ADDR 0x200000
#define ONE_WIRE_GPIO_OFFSET 21
#define ONE_WIRE_CONFIG_OUT writel_relaxed(ONE_WIRE_GPIO_ADDR, g_onewire_data->gpio_dir_set_addr)// OUT
#define ONE_WIRE_CONFIG_IN writel_relaxed(ONE_WIRE_GPIO_ADDR, g_onewire_data->gpio_dir_clr_addr)// IN
#define ONE_WIRE_OUT_HIGH writel_relaxed(ONE_WIRE_GPIO_ADDR, g_onewire_data->gpio_dout_set_addr)// OUT: 1
#define ONE_WIRE_OUT_LOW writel_relaxed(ONE_WIRE_GPIO_ADDR, g_onewire_data->gpio_dout_clr_addr)// OUT: 0
struct onewire_gpio_data {
struct platform_device *pdev;
struct device *dev;
int ow_gpio;
struct gpio_desc *ow_gpio_desc;
struct gpio_chip *ow_gpio_chip;
void *gpio_dir_addr;// [rw]0:in 1:out
void *gpio_dir_set_addr;// [w]0:keep 1:set
void *gpio_dir_clr_addr;// [w]0:keep 1:clr
void *gpio_dout_addr;// [rw]0:L 1:H
void *gpio_dout_set_addr;// [w]0:keep 1:set
void *gpio_dout_clr_addr;// [w]0:keep 1:clr
void *gpio_din_addr;// [R]
raw_spinlock_t lock;
struct pinctrl *ow_gpio_pinctrl;
struct pinctrl_state *pinctrl_state_active;
struct pinctrl_state *pinctrl_state_sleep;
int version;
int gpio_num;
unsigned int onewire_gpio_dir_addr;
unsigned int onewire_gpio_dir_set_addr;
unsigned int onewire_gpio_dir_clr_addr;
unsigned int onewire_gpio_dout_addr;
unsigned int onewire_gpio_dout_set_addr;
unsigned int onewire_gpio_dout_clr_addr;
unsigned int onewire_gpio_din_addr;
};
static struct class *onewire_class;
static int onewire_major;
static int onewire_gpio_detected;
static struct onewire_gpio_data *g_onewire_data;
void Delay_us(unsigned int T)
{
udelay(T);
}
EXPORT_SYMBOL(Delay_us);
void Delay_ns(unsigned int T)
{
ndelay(T);
}
EXPORT_SYMBOL(Delay_ns);
unsigned char ow_reset(void)
{
unsigned char presence = 0xFF;
unsigned long flags;
raw_spin_lock_irqsave(&g_onewire_data->lock, flags);
ONE_WIRE_CONFIG_OUT;
ONE_WIRE_OUT_LOW;
Delay_us(50);// 48
ONE_WIRE_OUT_HIGH;
ONE_WIRE_CONFIG_IN;
Delay_us(7);
presence = (unsigned char)((readl_relaxed(g_onewire_data->gpio_din_addr) \
& ONE_WIRE_GPIO_ADDR) >> ONE_WIRE_GPIO_OFFSET); // Read
Delay_us(50);
raw_spin_unlock_irqrestore(&g_onewire_data->lock, flags);
return presence;
}
EXPORT_SYMBOL(ow_reset);
unsigned char read_bit(void)
{
unsigned int vamm;
ONE_WIRE_CONFIG_OUT;
ONE_WIRE_OUT_LOW;
Delay_us(1);////
ONE_WIRE_CONFIG_IN;
Delay_ns(500);//
vamm = readl_relaxed(g_onewire_data->gpio_din_addr); // Read
Delay_us(5);
ONE_WIRE_OUT_HIGH;
ONE_WIRE_CONFIG_OUT;
Delay_us(6);
return((unsigned char)((vamm & ONE_WIRE_GPIO_ADDR) >> ONE_WIRE_GPIO_OFFSET));
}
void write_bit(char bitval)
{
ONE_WIRE_OUT_LOW;
Delay_us(1);//
if (bitval != 0)
ONE_WIRE_OUT_HIGH;
Delay_us(10);
ONE_WIRE_OUT_HIGH;
Delay_us(6);
}
unsigned char read_byte(void)
{
unsigned char i;
unsigned char value = 0;
unsigned long flags;
raw_spin_lock_irqsave(&g_onewire_data->lock, flags);
for (i = 0; i < 8; i++) {
if (read_bit())
value |= 0x01 << i;// reads byte in, one byte at a time and then shifts it left
}
raw_spin_unlock_irqrestore(&g_onewire_data->lock, flags);
return value;
}
EXPORT_SYMBOL(read_byte);
void write_byte(char val)
{
unsigned char i;
unsigned char temp;
unsigned long flags;
raw_spin_lock_irqsave(&g_onewire_data->lock, flags);
ONE_WIRE_CONFIG_OUT;
// writes byte, one bit at a time
for (i = 0; i < 8; i++) {
temp = val >> i ; // shifts val right ‘i’ spaces
temp &= 0x01; // copy that bit to temp
write_bit(temp); // write bit in temp into
}
raw_spin_unlock_irqrestore(&g_onewire_data->lock, flags);
}
EXPORT_SYMBOL(write_byte);
int onewire_gpio_get_status(void)
{
return onewire_gpio_detected;
}
EXPORT_SYMBOL(onewire_gpio_get_status);
// parse dts
static int onewire_gpio_parse_dt(struct device *dev,
struct onewire_gpio_data *pdata)
{
int error, val;
struct device_node *np = dev->of_node;
ow_log("%s", __func__);
// parse version
pdata->version = 0;
error = of_property_read_u32(np, "xiaomi,version", &val);
if (error && (error != -EINVAL))
ow_err("Unable to read version\n");
else if (error != -EINVAL)
pdata->version = val;
// parse gpio
pdata->ow_gpio = of_get_named_gpio_flags(np,
"xiaomi,ow_gpio", 0, NULL);
ow_dbg("ow_gpio: %d\n", pdata->ow_gpio);
// parse gpio_num
pdata->gpio_num = 0;
error = of_property_read_u32(np, "xiaomi,gpio_number", &val);
if (error && (error != -EINVAL))
ow_err("Unable to read gpio number.\n");
else if (error != -EINVAL)
pdata->gpio_num = val;
ow_log("gpio_num: %d\n", pdata->gpio_num);
error = of_property_read_u32(np, "mi,onewire-gpio-dir-addr", &val);
if (error < 0)
ow_err("Unable to read onewire-gpio-dir-addr.\n");
else
pdata->onewire_gpio_dir_addr = val;
ow_log("onewire_gpio_dir_addr: %04x\n", pdata->onewire_gpio_dir_addr);
error = of_property_read_u32(np, "mi,onewire-gpio-dir-set-addr", &val);
if (error < 0)
ow_err("Unable to read onewire-gpio-dir-set-addr.\n");
else
pdata->onewire_gpio_dir_set_addr = val;
ow_log("onewire_gpio_dir_set_addr: %04x\n", pdata->onewire_gpio_dir_set_addr);
error = of_property_read_u32(np, "mi,onewire-gpio-dir-clr-addr", &val);
if (error < 0)
ow_err("Unable to read onewire-gpio-dir-clr-addr.\n");
else
pdata->onewire_gpio_dir_clr_addr = val;
ow_log("onewire_gpio_dir_clr_addr: %04x\n", pdata->onewire_gpio_dir_clr_addr);
error = of_property_read_u32(np, "mi,onewire-gpio-dout-addr", &val);
if (error < 0)
ow_err("Unable to read onewire-gpio-dout-addr.\n");
else
pdata->onewire_gpio_dout_addr = val;
ow_log("onewire_gpio_dout_addr: %04x\n", pdata->onewire_gpio_dout_addr);
error = of_property_read_u32(np, "mi,onewire-gpio-dout-set-addr", &val);
if (error < 0)
ow_err("Unable to read onewire-gpio-dout-set-addr.\n");
else
pdata->onewire_gpio_dout_set_addr = val;
ow_log("onewire_gpio_dout_set_addr: %04x\n", pdata->onewire_gpio_dout_set_addr);
error = of_property_read_u32(np, "mi,onewire-gpio-dout-clr-addr", &val);
if (error < 0)
ow_err("Unable to read onewire-gpio-dout-clr-addr.\n");
else
pdata->onewire_gpio_dout_clr_addr = val;
ow_log("onewire_gpio_dout_clr_addr: %04x\n", pdata->onewire_gpio_dout_clr_addr);
error = of_property_read_u32(np, "mi,onewire-gpio-din-addr", &val);
if (error < 0)
ow_err("Unable to read onewire-gpio-din-addr.\n");
else
pdata->onewire_gpio_din_addr = val;
ow_log("onewire_gpio_din_addr: %04x\n", pdata->onewire_gpio_din_addr);
return 0;
}
// pinctrl init
static int onewire_gpio_pinctrl_init(struct onewire_gpio_data *onewire_data)
{
int retval;
ow_log("%s", __func__);
onewire_data->ow_gpio_pinctrl = devm_pinctrl_get(&onewire_data->pdev->dev);
if (IS_ERR_OR_NULL(onewire_data->ow_gpio_pinctrl)) {
retval = PTR_ERR(onewire_data->ow_gpio_pinctrl);
ow_err("Target does not use pinctrl %d\n", retval);
goto ow_gpio_err_pinctrl_get;
}
onewire_data->pinctrl_state_active
= pinctrl_lookup_state(onewire_data->ow_gpio_pinctrl,
"onewire_active");
if (IS_ERR_OR_NULL(onewire_data->pinctrl_state_active)) {
retval = PTR_ERR(onewire_data->pinctrl_state_active);
ow_err("Can not lookup onewire_active pinstate %d\n", retval);
goto ow_gpio_err_pinctrl_lookup;
}
onewire_data->pinctrl_state_sleep
= pinctrl_lookup_state(onewire_data->ow_gpio_pinctrl,
"onewire_sleep");
if (IS_ERR_OR_NULL(onewire_data->pinctrl_state_sleep)) {
retval = PTR_ERR(onewire_data->pinctrl_state_sleep);
ow_err("Can not lookup onewire_sleep pinstate %d\n", retval);
goto ow_gpio_err_pinctrl_lookup;
}
return 0;
ow_gpio_err_pinctrl_get:
devm_pinctrl_put(onewire_data->ow_gpio_pinctrl);
ow_gpio_err_pinctrl_lookup:
onewire_data->ow_gpio_pinctrl = NULL;
return retval;
}
// read data from file
static ssize_t onewire_gpio_ow_gpio_status_read(struct device *dev,
struct device_attribute *attr, char *buf)
{
int status;
struct onewire_gpio_data *onewire_data = dev_get_drvdata(dev);
status = gpio_get_value(onewire_data->ow_gpio);
return scnprintf(buf, PAGE_SIZE, "%d", status);
}
// write data to file
static ssize_t onewire_gpio_ow_gpio_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned char result = 0x01;
int buf_int;
unsigned char i;
unsigned char RomID[8] = {0};
if (sscanf(buf, "%1u", &buf_int) != 1)
return -EINVAL;
if (buf_int == 0) {
ONE_WIRE_OUT_LOW;
ow_log("gpio : OUT 0");
} else if (buf_int == 1) {
ONE_WIRE_OUT_HIGH;
ow_log("gpio : OUT 1");
} else if (buf_int == 2) {
ONE_WIRE_CONFIG_OUT;
ow_log("gpio : OUT");
} else if (buf_int == 3) {
ONE_WIRE_CONFIG_IN;
ow_log("gpio : IN");
} else if (buf_int == 4) {
result = ow_reset();
if (result)
ow_log("ow_reset: no device.result = %02x", result);
else
ow_log("ow_reset: device exist.result = %02x", result);
} else if (buf_int == 5) {
result = read_bit();
ow_log("read_bit: %02x", result);
} else if (buf_int == 6) {
write_bit(0x01);
ow_log("write_bit 0");
} else if (buf_int == 7) {
result = ow_reset();
if (result)
ow_log("ow_reset: no device.result = %02x", result);
else
ow_log("ow_reset: device exist.result = %02x", result);
ow_dbg("Ready to write 0x33 to maxim IC!\n");
write_byte(0x33);
for (i = 0; i < 8; i++)
RomID[i] = read_byte();
ow_log("RomID = %02x%02x%02x%02x%02x%02x%02x%02x\n", RomID[0], RomID[1], RomID[2], RomID[3], RomID[4], RomID[5], RomID[6], RomID[7]);
} else if (buf_int == 8) {
ONE_WIRE_CONFIG_OUT;
ONE_WIRE_OUT_HIGH;
ONE_WIRE_OUT_LOW;
ONE_WIRE_OUT_HIGH;
ONE_WIRE_OUT_LOW;
ONE_WIRE_OUT_HIGH;
ONE_WIRE_OUT_LOW;
ONE_WIRE_OUT_HIGH;
ONE_WIRE_OUT_LOW;
ONE_WIRE_OUT_HIGH;
ONE_WIRE_OUT_LOW;
Delay_us(1000);
ONE_WIRE_OUT_HIGH;
Delay_us(1);
ONE_WIRE_OUT_LOW;
Delay_us(1);
ONE_WIRE_OUT_HIGH;
Delay_us(1);
ONE_WIRE_OUT_LOW;
Delay_us(1);
ONE_WIRE_OUT_HIGH;
Delay_us(1);
ONE_WIRE_OUT_LOW;
Delay_us(1);
ONE_WIRE_OUT_HIGH;
Delay_us(1);
ONE_WIRE_OUT_LOW;
Delay_us(1);
ONE_WIRE_OUT_HIGH;
Delay_us(1);
ONE_WIRE_OUT_LOW;
Delay_us(1);
Delay_us(1000);
ONE_WIRE_OUT_HIGH;
Delay_us(5);
ONE_WIRE_OUT_LOW;
Delay_us(5);
ONE_WIRE_OUT_HIGH;
Delay_us(5);
ONE_WIRE_OUT_LOW;
Delay_us(5);
ONE_WIRE_OUT_HIGH;
Delay_us(5);
ONE_WIRE_OUT_LOW;
Delay_us(5);
ONE_WIRE_OUT_HIGH;
Delay_us(5);
ONE_WIRE_OUT_LOW;
Delay_us(5);
ONE_WIRE_OUT_HIGH;
Delay_us(5);
ONE_WIRE_OUT_LOW;
Delay_us(5);
}
return count;
}
static DEVICE_ATTR(ow_gpio, S_IRUGO | S_IWUSR | S_IWGRP,
onewire_gpio_ow_gpio_status_read,
onewire_gpio_ow_gpio_store);
static int onewire_gpio_probe(struct platform_device *pdev)
{
int retval = 0;
struct onewire_gpio_data *onewire_data;
struct kobject *p;
ow_log("%s", __func__);
if (!pdev->dev.of_node || !of_device_is_available(pdev->dev.of_node))
return -ENODEV;
if (pdev->dev.of_node) {
onewire_data = devm_kzalloc(&pdev->dev,
sizeof(struct onewire_gpio_data),
GFP_KERNEL);
if (!onewire_data) {
ow_err("Failed to allocate memory\n");
return -ENOMEM;
}
retval = onewire_gpio_parse_dt(&pdev->dev, onewire_data);
if (retval) {
retval = -EINVAL;
goto onewire_parse_dt_err;
}
} else {
onewire_data = pdev->dev.platform_data;
}
if (!onewire_data) {
ow_err("No platform data found\n");
return -EINVAL;
}
g_onewire_data = onewire_data;
onewire_data->pdev = pdev;
platform_set_drvdata(pdev, onewire_data);
raw_spin_lock_init(&g_onewire_data->lock);
// pinctrl init
retval = onewire_gpio_pinctrl_init(onewire_data);
if (!retval && onewire_data->ow_gpio_pinctrl) {
retval = pinctrl_select_state(onewire_data->ow_gpio_pinctrl,
onewire_data->pinctrl_state_active);
if (retval < 0)
ow_err("Failed to select active pinstate %d\n", retval);
}
if (retval)
goto onewire_pinctrl_err;
// request onewire gpio
gpio_free(onewire_data->ow_gpio);
if (gpio_is_valid(onewire_data->ow_gpio)) {
retval = gpio_request(onewire_data->ow_gpio,
"onewire gpio");
} else {
retval = -EINVAL;
}
if (retval) {
ow_err("request onewire gpio failed, retval=%d\n",
retval);
goto onewire_ow_gpio_err;
}
// gpio output 1
gpio_direction_output(onewire_data->ow_gpio, 1);
onewire_data->ow_gpio_desc = gpio_to_desc(onewire_data->ow_gpio);
onewire_data->ow_gpio_chip = gpiod_to_chip(onewire_data->ow_gpio_desc);
onewire_data->gpio_dir_addr = devm_ioremap(&pdev->dev,
(uint32_t)onewire_data->onewire_gpio_dir_addr, 0x4);
onewire_data->gpio_dir_set_addr = devm_ioremap(&pdev->dev,
(uint32_t)onewire_data->onewire_gpio_dir_set_addr, 0x4);
onewire_data->gpio_dir_clr_addr = devm_ioremap(&pdev->dev,
(uint32_t)onewire_data->onewire_gpio_dir_clr_addr, 0x4);
onewire_data->gpio_dout_addr = devm_ioremap(&pdev->dev,
(uint32_t)onewire_data->onewire_gpio_dout_addr, 0x4);
onewire_data->gpio_dout_set_addr = devm_ioremap(&pdev->dev,
(uint32_t)onewire_data->onewire_gpio_dout_set_addr, 0x4);
onewire_data->gpio_dout_clr_addr = devm_ioremap(&pdev->dev,
(uint32_t)onewire_data->onewire_gpio_dout_clr_addr, 0x4);
onewire_data->gpio_din_addr = devm_ioremap(&pdev->dev,
(uint32_t)onewire_data->onewire_gpio_din_addr, 0x4);
// create device node
onewire_data->dev = device_create(onewire_class,
pdev->dev.parent->parent, onewire_major, onewire_data, "onewirectrl");
if (IS_ERR(onewire_data->dev)) {
ow_err("Failed to create interface device\n");
goto onewire_interface_dev_create_err;
}
p = &onewire_data->dev->kobj;
// create attr file
retval = sysfs_create_file(p, &dev_attr_ow_gpio.attr);
if (retval < 0) {
ow_err("Failed to create sysfs attr file\n");
goto onewire_sysfs_ow_gpio_err;
}
retval = sysfs_create_link(&onewire_data->dev->kobj, &pdev->dev.kobj,
"pltdev");
if (retval) {
ow_err("Failed to create sysfs link\n");
goto onewire_syfs_create_link_err;
}
return 0;
onewire_syfs_create_link_err:
if (gpio_is_valid(onewire_data->ow_gpio))
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_ow_gpio.attr);
onewire_sysfs_ow_gpio_err:
device_destroy(onewire_class, onewire_major);
onewire_interface_dev_create_err:
if (gpio_is_valid(onewire_data->ow_gpio))
gpio_free(onewire_data->ow_gpio);
onewire_ow_gpio_err:
onewire_pinctrl_err:
onewire_parse_dt_err:
kfree(onewire_data);
return retval;
}
static int onewire_gpio_remove(struct platform_device *pdev)
{
struct onewire_gpio_data *onewire_data = platform_get_drvdata(pdev);
if (gpio_is_valid(onewire_data->ow_gpio)) {
sysfs_remove_file(&pdev->dev.kobj, &dev_attr_ow_gpio.attr);
gpio_free(onewire_data->ow_gpio);
}
kfree(onewire_data);
return 0;
}
static long onewire_dev_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
ow_dbg("%d, cmd: 0x%x\n", __LINE__, cmd);
return 0;
}
static int onewire_dev_open(struct inode *inode, struct file *file)
{
return 0;
}
static int onewire_dev_release(struct inode *inode, struct file *file)
{
return 0;
}
static const struct file_operations onewire_dev_fops = {
.owner = THIS_MODULE,
.open = onewire_dev_open,
.unlocked_ioctl = onewire_dev_ioctl,
.release = onewire_dev_release,
};
static const struct of_device_id onewire_gpio_dt_match[] = {
{.compatible = "xiaomi,onewire_gpio"},
{},
};
static struct platform_driver onewire_gpio_driver = {
.driver = {
.owner = THIS_MODULE,
.name = "onewire_gpio",
.of_match_table = onewire_gpio_dt_match,
},
.probe = onewire_gpio_probe,
.remove = onewire_gpio_remove,
};
static int __init onewire_gpio_init(void)
{
int retval;
onewire_gpio_detected = false;
ow_log("onewire gpio init entry.");
onewire_class = class_create(THIS_MODULE, "onewire");
if (IS_ERR(onewire_class)) {
ow_err("coudn't create class");
return PTR_ERR(onewire_class);
}
onewire_major = register_chrdev(0, "onewirectrl", &onewire_dev_fops);
if (onewire_major < 0) {
ow_err("failed to allocate char dev\n");
retval = onewire_major;
goto class_unreg;
}
return platform_driver_register(&onewire_gpio_driver);
class_unreg:
class_destroy(onewire_class);
return retval;
}
static void __exit onewire_gpio_exit(void)
{
ow_log("onewire gpio exit entry.");
platform_driver_unregister(&onewire_gpio_driver);
unregister_chrdev(onewire_major, "onewirectrl");
class_destroy(onewire_class);
}
module_init(onewire_gpio_init);
module_exit(onewire_gpio_exit);
MODULE_AUTHOR("xiaomi Inc.");
MODULE_DESCRIPTION("onewire driver");
MODULE_LICENSE("GPL");