/* * arm_gpio_lock register: * bit[31] lock status: active if set * bit[15:0] set lock * The lock is enabled only if 0xd42f is written to this field
*/ #define YU_ARM_GPIO_LOCK_ADDR 0x2801088 #define YU_ARM_GPIO_LOCK_SIZE 0x8 #define YU_LOCK_ACTIVE_BIT(val) (val >> 31) #define YU_ARM_GPIO_LOCK_ACQUIRE 0xd42f #define YU_ARM_GPIO_LOCK_RELEASE 0x0
/* Request memory region and map yu_arm_gpio_lock resource */ staticint mlxbf2_gpio_get_lock_res(struct platform_device *pdev)
{ struct device *dev = &pdev->dev; struct resource *res;
resource_size_t size; int ret = 0;
mutex_lock(yu_arm_gpio_lock_param.lock);
/* Check if the memory map already exists */ if (yu_arm_gpio_lock_param.io) gotoexit;
res = yu_arm_gpio_lock_param.res;
size = resource_size(res);
if (!devm_request_mem_region(dev, res->start, size, res->name)) {
ret = -EFAULT; gotoexit;
}
yu_arm_gpio_lock_param.io = devm_ioremap(dev, res->start, size); if (!yu_arm_gpio_lock_param.io)
ret = -ENOMEM;
exit:
mutex_unlock(yu_arm_gpio_lock_param.lock);
return ret;
}
/* * Acquire the YU arm_gpio_lock to be able to change the direction * mode. If the lock_active bit is already set, return an error.
*/ staticint mlxbf2_gpio_lock_acquire(struct mlxbf2_gpio_context *gs)
{
u32 arm_gpio_lock_val;
/* * When lock active bit[31] is set, ModeX is write enabled
*/ if (YU_LOCK_ACTIVE_BIT(arm_gpio_lock_val)) {
raw_spin_unlock(&gs->gc.bgpio_lock);
mutex_unlock(yu_arm_gpio_lock_param.lock); return -EINVAL;
}
/* * Release the YU arm_gpio_lock after changing the direction mode.
*/ staticvoid mlxbf2_gpio_lock_release(struct mlxbf2_gpio_context *gs)
__releases(&gs->gc.bgpio_lock)
__releases(yu_arm_gpio_lock_param.lock)
{
writel(YU_ARM_GPIO_LOCK_RELEASE, yu_arm_gpio_lock_param.io);
raw_spin_unlock(&gs->gc.bgpio_lock);
mutex_unlock(yu_arm_gpio_lock_param.lock);
}
/* * mode0 and mode1 are both locked by the gpio_lock field. * * Together, mode0 and mode1 define the gpio Mode dependeing also * on Reg_DataOut. * * {mode1,mode0}:{Reg_DataOut=0,Reg_DataOut=1}->{DataOut=0,DataOut=1} * * {0,0}:Reg_DataOut{0,1}->{Z,Z} Input PAD * {0,1}:Reg_DataOut{0,1}->{0,1} Full drive Output PAD * {1,0}:Reg_DataOut{0,1}->{0,Z} 0-set PAD to low, 1-float * {1,1}:Reg_DataOut{0,1}->{Z,1} 0-float, 1-set PAD to high
*/
/* * Although the arm_gpio_lock was set in the probe function, check again * if it is still enabled to be able to write to the ModeX registers.
*/
ret = mlxbf2_gpio_lock_acquire(gs); if (ret < 0) return ret;
/* * Set output direction: * {mode1,mode0} = {0,1}
*/ staticint mlxbf2_gpio_direction_output(struct gpio_chip *chip, unsignedint offset, int value)
{ struct mlxbf2_gpio_context *gs = gpiochip_get_data(chip); int ret = 0;
/* * Although the arm_gpio_lock was set in the probe function, * check again it is still enabled to be able to write to the * ModeX registers.
*/
ret = mlxbf2_gpio_lock_acquire(gs); if (ret < 0) return ret;
irq = platform_get_irq_optional(pdev, 0); if (irq >= 0) {
girq = &gs->gc.irq;
gpio_irq_chip_set_chip(girq, &mlxbf2_gpio_irq_chip);
girq->handler = handle_simple_irq;
girq->default_type = IRQ_TYPE_NONE; /* This will let us handle the parent IRQ in the driver */
girq->num_parents = 0;
girq->parents = NULL;
girq->parent_handler = NULL;
/* * Directly request the irq here instead of passing * a flow-handler because the irq is shared.
*/
ret = devm_request_irq(dev, irq, mlxbf2_gpio_irq_handler,
IRQF_SHARED, name, gs); if (ret) {
dev_err(dev, "failed to request IRQ"); return ret;
}
}
platform_set_drvdata(pdev, gs);
ret = devm_gpiochip_add_data(dev, &gs->gc, gs); if (ret) {
dev_err(dev, "Failed adding memory mapped gpiochip\n"); return ret;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.