hc
2023-12-11 6778948f9de86c3cfaf36725a7c87dcff9ba247f
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
// SPDX-License-Identifier: GPL-2.0-only
/*
 *  ARM IOC/IOMD i2c driver.
 *
 *  Copyright (C) 2000 Russell King
 *
 *  On Acorn machines, the following i2c devices are on the bus:
 *    - PCF8583 real time clock & static RAM
 */
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/io.h>
 
#include <mach/hardware.h>
#include <asm/hardware/ioc.h>
 
#define FORCE_ONES    0xdc
#define SCL        0x02
#define SDA        0x01
 
/*
 * We must preserve all non-i2c output bits in IOC_CONTROL.
 * Note also that we need to preserve the value of SCL and
 * SDA outputs as well (which may be different from the
 * values read back from IOC_CONTROL).
 */
static u_int force_ones;
 
static void ioc_setscl(void *data, int state)
{
   u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
   u_int ones = force_ones;
 
   if (state)
       ones |= SCL;
   else
       ones &= ~SCL;
 
   force_ones = ones;
 
     ioc_writeb(ioc_control | ones, IOC_CONTROL);
}
 
static void ioc_setsda(void *data, int state)
{
   u_int ioc_control = ioc_readb(IOC_CONTROL) & ~(SCL | SDA);
   u_int ones = force_ones;
 
   if (state)
       ones |= SDA;
   else
       ones &= ~SDA;
 
   force_ones = ones;
 
     ioc_writeb(ioc_control | ones, IOC_CONTROL);
}
 
static int ioc_getscl(void *data)
{
   return (ioc_readb(IOC_CONTROL) & SCL) != 0;
}
 
static int ioc_getsda(void *data)
{
   return (ioc_readb(IOC_CONTROL) & SDA) != 0;
}
 
static struct i2c_algo_bit_data ioc_data = {
   .setsda        = ioc_setsda,
   .setscl        = ioc_setscl,
   .getsda        = ioc_getsda,
   .getscl        = ioc_getscl,
   .udelay        = 80,
   .timeout    = HZ,
};
 
static struct i2c_adapter ioc_ops = {
   .nr            = 0,
   .name            = "ioc",
   .algo_data        = &ioc_data,
};
 
static int __init i2c_ioc_init(void)
{
   force_ones = FORCE_ONES | SCL | SDA;
 
   return i2c_bit_add_numbered_bus(&ioc_ops);
}
 
module_init(i2c_ioc_init);
 
MODULE_AUTHOR("Russell King <linux@armlinux.org.uk>");
MODULE_DESCRIPTION("ARM IOC/IOMD i2c driver");
MODULE_LICENSE("GPL v2");