Merge tag 'rtc-6.8' of git://git.kernel.org/pub/scm/linux/kernel/git/abelloni/linux
[linux-2.6-microblaze.git] / drivers / gpu / drm / loongson / lsdc_i2c.c
1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Copyright (C) 2023 Loongson Technology Corporation Limited
4  */
5
6 #include <drm/drm_managed.h>
7
8 #include "lsdc_drv.h"
9 #include "lsdc_output.h"
10
11 /*
12  * __lsdc_gpio_i2c_set - set the state of a gpio pin indicated by mask
13  * @mask: gpio pin mask
14  * @state: "0" for low, "1" for high
15  */
16 static void __lsdc_gpio_i2c_set(struct lsdc_i2c * const li2c, int mask, int state)
17 {
18         struct lsdc_device *ldev = to_lsdc(li2c->ddev);
19         unsigned long flags;
20         u8 val;
21
22         spin_lock_irqsave(&ldev->reglock, flags);
23
24         if (state) {
25                 /*
26                  * Setting this pin as input directly, write 1 for input.
27                  * The external pull-up resistor will pull the level up
28                  */
29                 val = readb(li2c->dir_reg);
30                 val |= mask;
31                 writeb(val, li2c->dir_reg);
32         } else {
33                 /* First set this pin as output, write 0 for output */
34                 val = readb(li2c->dir_reg);
35                 val &= ~mask;
36                 writeb(val, li2c->dir_reg);
37
38                 /* Then, make this pin output 0 */
39                 val = readb(li2c->dat_reg);
40                 val &= ~mask;
41                 writeb(val, li2c->dat_reg);
42         }
43
44         spin_unlock_irqrestore(&ldev->reglock, flags);
45 }
46
47 /*
48  * __lsdc_gpio_i2c_get - read value back from the gpio pin indicated by mask
49  * @mask: gpio pin mask
50  * return "0" for low, "1" for high
51  */
52 static int __lsdc_gpio_i2c_get(struct lsdc_i2c * const li2c, int mask)
53 {
54         struct lsdc_device *ldev = to_lsdc(li2c->ddev);
55         unsigned long flags;
56         u8 val;
57
58         spin_lock_irqsave(&ldev->reglock, flags);
59
60         /* First set this pin as input */
61         val = readb(li2c->dir_reg);
62         val |= mask;
63         writeb(val, li2c->dir_reg);
64
65         /* Then get level state from this pin */
66         val = readb(li2c->dat_reg);
67
68         spin_unlock_irqrestore(&ldev->reglock, flags);
69
70         return (val & mask) ? 1 : 0;
71 }
72
73 static void lsdc_gpio_i2c_set_sda(void *i2c, int state)
74 {
75         struct lsdc_i2c * const li2c = (struct lsdc_i2c *)i2c;
76         /* set state on the li2c->sda pin */
77         return __lsdc_gpio_i2c_set(li2c, li2c->sda, state);
78 }
79
80 static void lsdc_gpio_i2c_set_scl(void *i2c, int state)
81 {
82         struct lsdc_i2c * const li2c = (struct lsdc_i2c *)i2c;
83         /* set state on the li2c->scl pin */
84         return __lsdc_gpio_i2c_set(li2c, li2c->scl, state);
85 }
86
87 static int lsdc_gpio_i2c_get_sda(void *i2c)
88 {
89         struct lsdc_i2c * const li2c = (struct lsdc_i2c *)i2c;
90         /* read value from the li2c->sda pin */
91         return __lsdc_gpio_i2c_get(li2c, li2c->sda);
92 }
93
94 static int lsdc_gpio_i2c_get_scl(void *i2c)
95 {
96         struct lsdc_i2c * const li2c = (struct lsdc_i2c *)i2c;
97         /* read the value from the li2c->scl pin */
98         return __lsdc_gpio_i2c_get(li2c, li2c->scl);
99 }
100
101 static void lsdc_destroy_i2c(struct drm_device *ddev, void *data)
102 {
103         struct lsdc_i2c *li2c = (struct lsdc_i2c *)data;
104
105         if (li2c) {
106                 i2c_del_adapter(&li2c->adapter);
107                 kfree(li2c);
108         }
109 }
110
111 /*
112  * The DC in ls7a1000/ls7a2000/ls2k2000 has builtin gpio hardware
113  *
114  * @reg_base: gpio reg base
115  * @index: output channel index, 0 for PIPE0, 1 for PIPE1
116  */
117 int lsdc_create_i2c_chan(struct drm_device *ddev,
118                          struct lsdc_display_pipe *dispipe,
119                          unsigned int index)
120 {
121         struct lsdc_device *ldev = to_lsdc(ddev);
122         struct i2c_adapter *adapter;
123         struct lsdc_i2c *li2c;
124         int ret;
125
126         li2c = kzalloc(sizeof(*li2c), GFP_KERNEL);
127         if (!li2c)
128                 return -ENOMEM;
129
130         dispipe->li2c = li2c;
131
132         if (index == 0) {
133                 li2c->sda = 0x01;  /* pin 0 */
134                 li2c->scl = 0x02;  /* pin 1 */
135         } else if (index == 1) {
136                 li2c->sda = 0x04;  /* pin 2 */
137                 li2c->scl = 0x08;  /* pin 3 */
138         } else {
139                 return -ENOENT;
140         }
141
142         li2c->ddev = ddev;
143         li2c->dir_reg = ldev->reg_base + LS7A_DC_GPIO_DIR_REG;
144         li2c->dat_reg = ldev->reg_base + LS7A_DC_GPIO_DAT_REG;
145
146         li2c->bit.setsda = lsdc_gpio_i2c_set_sda;
147         li2c->bit.setscl = lsdc_gpio_i2c_set_scl;
148         li2c->bit.getsda = lsdc_gpio_i2c_get_sda;
149         li2c->bit.getscl = lsdc_gpio_i2c_get_scl;
150         li2c->bit.udelay = 5;
151         li2c->bit.timeout = usecs_to_jiffies(2200);
152         li2c->bit.data = li2c;
153
154         adapter = &li2c->adapter;
155         adapter->algo_data = &li2c->bit;
156         adapter->owner = THIS_MODULE;
157         adapter->class = I2C_CLASS_DDC;
158         adapter->dev.parent = ddev->dev;
159         adapter->nr = -1;
160
161         snprintf(adapter->name, sizeof(adapter->name), "lsdc-i2c%u", index);
162
163         i2c_set_adapdata(adapter, li2c);
164
165         ret = i2c_bit_add_bus(adapter);
166         if (ret) {
167                 kfree(li2c);
168                 return ret;
169         }
170
171         ret = drmm_add_action_or_reset(ddev, lsdc_destroy_i2c, li2c);
172         if (ret)
173                 return ret;
174
175         drm_info(ddev, "%s(sda pin mask=%u, scl pin mask=%u) created\n",
176                  adapter->name, li2c->sda, li2c->scl);
177
178         return 0;
179 }