brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · ce90c25 Raw
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