162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * i2sbus driver -- bus control routines 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright 2006 Johannes Berg <johannes@sipsolutions.net> 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/delay.h> 1062306a36Sopenharmony_ci#include <linux/slab.h> 1162306a36Sopenharmony_ci#include <linux/io.h> 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <asm/prom.h> 1462306a36Sopenharmony_ci#include <asm/macio.h> 1562306a36Sopenharmony_ci#include <asm/pmac_feature.h> 1662306a36Sopenharmony_ci#include <asm/pmac_pfunc.h> 1762306a36Sopenharmony_ci#include <asm/keylargo.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include "i2sbus.h" 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ciint i2sbus_control_init(struct macio_dev* dev, struct i2sbus_control **c) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci *c = kzalloc(sizeof(struct i2sbus_control), GFP_KERNEL); 2462306a36Sopenharmony_ci if (!*c) 2562306a36Sopenharmony_ci return -ENOMEM; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci INIT_LIST_HEAD(&(*c)->list); 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci (*c)->macio = dev->bus->chip; 3062306a36Sopenharmony_ci return 0; 3162306a36Sopenharmony_ci} 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_civoid i2sbus_control_destroy(struct i2sbus_control *c) 3462306a36Sopenharmony_ci{ 3562306a36Sopenharmony_ci kfree(c); 3662306a36Sopenharmony_ci} 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci/* this is serialised externally */ 3962306a36Sopenharmony_ciint i2sbus_control_add_dev(struct i2sbus_control *c, 4062306a36Sopenharmony_ci struct i2sbus_dev *i2sdev) 4162306a36Sopenharmony_ci{ 4262306a36Sopenharmony_ci struct device_node *np; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci np = i2sdev->sound.ofdev.dev.of_node; 4562306a36Sopenharmony_ci i2sdev->enable = pmf_find_function(np, "enable"); 4662306a36Sopenharmony_ci i2sdev->cell_enable = pmf_find_function(np, "cell-enable"); 4762306a36Sopenharmony_ci i2sdev->clock_enable = pmf_find_function(np, "clock-enable"); 4862306a36Sopenharmony_ci i2sdev->cell_disable = pmf_find_function(np, "cell-disable"); 4962306a36Sopenharmony_ci i2sdev->clock_disable = pmf_find_function(np, "clock-disable"); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci /* if the bus number is not 0 or 1 we absolutely need to use 5262306a36Sopenharmony_ci * the platform functions -- there's nothing in Darwin that 5362306a36Sopenharmony_ci * would allow seeing a system behind what the FCRs are then, 5462306a36Sopenharmony_ci * and I don't want to go parsing a bunch of platform functions 5562306a36Sopenharmony_ci * by hand to try finding a system... */ 5662306a36Sopenharmony_ci if (i2sdev->bus_number != 0 && i2sdev->bus_number != 1 && 5762306a36Sopenharmony_ci (!i2sdev->enable || 5862306a36Sopenharmony_ci !i2sdev->cell_enable || !i2sdev->clock_enable || 5962306a36Sopenharmony_ci !i2sdev->cell_disable || !i2sdev->clock_disable)) { 6062306a36Sopenharmony_ci pmf_put_function(i2sdev->enable); 6162306a36Sopenharmony_ci pmf_put_function(i2sdev->cell_enable); 6262306a36Sopenharmony_ci pmf_put_function(i2sdev->clock_enable); 6362306a36Sopenharmony_ci pmf_put_function(i2sdev->cell_disable); 6462306a36Sopenharmony_ci pmf_put_function(i2sdev->clock_disable); 6562306a36Sopenharmony_ci return -ENODEV; 6662306a36Sopenharmony_ci } 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci list_add(&i2sdev->item, &c->list); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci return 0; 7162306a36Sopenharmony_ci} 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_civoid i2sbus_control_remove_dev(struct i2sbus_control *c, 7462306a36Sopenharmony_ci struct i2sbus_dev *i2sdev) 7562306a36Sopenharmony_ci{ 7662306a36Sopenharmony_ci /* this is serialised externally */ 7762306a36Sopenharmony_ci list_del(&i2sdev->item); 7862306a36Sopenharmony_ci if (list_empty(&c->list)) 7962306a36Sopenharmony_ci i2sbus_control_destroy(c); 8062306a36Sopenharmony_ci} 8162306a36Sopenharmony_ci 8262306a36Sopenharmony_ciint i2sbus_control_enable(struct i2sbus_control *c, 8362306a36Sopenharmony_ci struct i2sbus_dev *i2sdev) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci struct pmf_args args = { .count = 0 }; 8662306a36Sopenharmony_ci struct macio_chip *macio = c->macio; 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_ci if (i2sdev->enable) 8962306a36Sopenharmony_ci return pmf_call_one(i2sdev->enable, &args); 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (macio == NULL || macio->base == NULL) 9262306a36Sopenharmony_ci return -ENODEV; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci switch (i2sdev->bus_number) { 9562306a36Sopenharmony_ci case 0: 9662306a36Sopenharmony_ci /* these need to be locked or done through 9762306a36Sopenharmony_ci * newly created feature calls! */ 9862306a36Sopenharmony_ci MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_ENABLE); 9962306a36Sopenharmony_ci break; 10062306a36Sopenharmony_ci case 1: 10162306a36Sopenharmony_ci MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_ENABLE); 10262306a36Sopenharmony_ci break; 10362306a36Sopenharmony_ci default: 10462306a36Sopenharmony_ci return -ENODEV; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci return 0; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ciint i2sbus_control_cell(struct i2sbus_control *c, 11062306a36Sopenharmony_ci struct i2sbus_dev *i2sdev, 11162306a36Sopenharmony_ci int enable) 11262306a36Sopenharmony_ci{ 11362306a36Sopenharmony_ci struct pmf_args args = { .count = 0 }; 11462306a36Sopenharmony_ci struct macio_chip *macio = c->macio; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci switch (enable) { 11762306a36Sopenharmony_ci case 0: 11862306a36Sopenharmony_ci if (i2sdev->cell_disable) 11962306a36Sopenharmony_ci return pmf_call_one(i2sdev->cell_disable, &args); 12062306a36Sopenharmony_ci break; 12162306a36Sopenharmony_ci case 1: 12262306a36Sopenharmony_ci if (i2sdev->cell_enable) 12362306a36Sopenharmony_ci return pmf_call_one(i2sdev->cell_enable, &args); 12462306a36Sopenharmony_ci break; 12562306a36Sopenharmony_ci default: 12662306a36Sopenharmony_ci printk(KERN_ERR "i2sbus: INVALID CELL ENABLE VALUE\n"); 12762306a36Sopenharmony_ci return -ENODEV; 12862306a36Sopenharmony_ci } 12962306a36Sopenharmony_ci 13062306a36Sopenharmony_ci if (macio == NULL || macio->base == NULL) 13162306a36Sopenharmony_ci return -ENODEV; 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci switch (i2sdev->bus_number) { 13462306a36Sopenharmony_ci case 0: 13562306a36Sopenharmony_ci if (enable) 13662306a36Sopenharmony_ci MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE); 13762306a36Sopenharmony_ci else 13862306a36Sopenharmony_ci MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CELL_ENABLE); 13962306a36Sopenharmony_ci break; 14062306a36Sopenharmony_ci case 1: 14162306a36Sopenharmony_ci if (enable) 14262306a36Sopenharmony_ci MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE); 14362306a36Sopenharmony_ci else 14462306a36Sopenharmony_ci MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CELL_ENABLE); 14562306a36Sopenharmony_ci break; 14662306a36Sopenharmony_ci default: 14762306a36Sopenharmony_ci return -ENODEV; 14862306a36Sopenharmony_ci } 14962306a36Sopenharmony_ci return 0; 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ciint i2sbus_control_clock(struct i2sbus_control *c, 15362306a36Sopenharmony_ci struct i2sbus_dev *i2sdev, 15462306a36Sopenharmony_ci int enable) 15562306a36Sopenharmony_ci{ 15662306a36Sopenharmony_ci struct pmf_args args = { .count = 0 }; 15762306a36Sopenharmony_ci struct macio_chip *macio = c->macio; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci switch (enable) { 16062306a36Sopenharmony_ci case 0: 16162306a36Sopenharmony_ci if (i2sdev->clock_disable) 16262306a36Sopenharmony_ci return pmf_call_one(i2sdev->clock_disable, &args); 16362306a36Sopenharmony_ci break; 16462306a36Sopenharmony_ci case 1: 16562306a36Sopenharmony_ci if (i2sdev->clock_enable) 16662306a36Sopenharmony_ci return pmf_call_one(i2sdev->clock_enable, &args); 16762306a36Sopenharmony_ci break; 16862306a36Sopenharmony_ci default: 16962306a36Sopenharmony_ci printk(KERN_ERR "i2sbus: INVALID CLOCK ENABLE VALUE\n"); 17062306a36Sopenharmony_ci return -ENODEV; 17162306a36Sopenharmony_ci } 17262306a36Sopenharmony_ci 17362306a36Sopenharmony_ci if (macio == NULL || macio->base == NULL) 17462306a36Sopenharmony_ci return -ENODEV; 17562306a36Sopenharmony_ci 17662306a36Sopenharmony_ci switch (i2sdev->bus_number) { 17762306a36Sopenharmony_ci case 0: 17862306a36Sopenharmony_ci if (enable) 17962306a36Sopenharmony_ci MACIO_BIS(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT); 18062306a36Sopenharmony_ci else 18162306a36Sopenharmony_ci MACIO_BIC(KEYLARGO_FCR1, KL1_I2S0_CLK_ENABLE_BIT); 18262306a36Sopenharmony_ci break; 18362306a36Sopenharmony_ci case 1: 18462306a36Sopenharmony_ci if (enable) 18562306a36Sopenharmony_ci MACIO_BIS(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT); 18662306a36Sopenharmony_ci else 18762306a36Sopenharmony_ci MACIO_BIC(KEYLARGO_FCR1, KL1_I2S1_CLK_ENABLE_BIT); 18862306a36Sopenharmony_ci break; 18962306a36Sopenharmony_ci default: 19062306a36Sopenharmony_ci return -ENODEV; 19162306a36Sopenharmony_ci } 19262306a36Sopenharmony_ci return 0; 19362306a36Sopenharmony_ci} 194