179 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * Copyright (C) 2023 Loongson Technology Corporation Limited4 */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 mask13 * @mask: gpio pin mask14 * @state: "0" for low, "1" for high15 */16static 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 up28 */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 mask49 * @mask: gpio pin mask50 * return "0" for low, "1" for high51 */52static 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 73static 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 80static 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 87static 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 94static 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 101static 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 hardware113 *114 * @reg_base: gpio reg base115 * @index: output channel index, 0 for PIPE0, 1 for PIPE1116 */117int 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->dev.parent = ddev->dev;158 adapter->nr = -1;159 160 snprintf(adapter->name, sizeof(adapter->name), "lsdc-i2c%u", index);161 162 i2c_set_adapdata(adapter, li2c);163 164 ret = i2c_bit_add_bus(adapter);165 if (ret) {166 kfree(li2c);167 return ret;168 }169 170 ret = drmm_add_action_or_reset(ddev, lsdc_destroy_i2c, li2c);171 if (ret)172 return ret;173 174 drm_info(ddev, "%s(sda pin mask=%u, scl pin mask=%u) created\n",175 adapter->name, li2c->sda, li2c->scl);176 177 return 0;178}179