// ----------------------------------------------------------------------- // // Copyright 2008 H. Peter Anvin - All Rights Reserved // // This program is free software; you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, // Boston MA 02110-1301, USA; either version 2 of the License, or // (at your option) any later version; incorporated herein by reference. // // ----------------------------------------------------------------------- // // Sound DAC I2C controller // // The I2S DAC on the DE1 board need to be initialized via I2C. // module sound_i2c ( input rst_n, // Reset input clk, // System clock input clk_en, // Strobe (<= 1.6 MHz) inout i2c_scl, // I2C SCL inout i2c_sda // I2C SDA ); parameter i2c_addr = 7'h1A; // DAC I2C address // Only need to set registers 15 + 0-9 parameter i2c_rom_stop = 4'd9; // Last valid register number reg [3:0] i2c_rom_a; wire [8:0] i2c_rom_q; reg [4:0] i2c_bit_ctr; reg [1:0] i2c_qtr; reg abn; reg sda; reg scl; reg i2c_active = 1'b0; wire i2c_stop = i2c_rom_a == i2c_rom_stop; // Output drivers: all outputs are open drain assign i2c_scl = scl ? 1'bz : 1'b0; assign i2c_sda = sda ? 1'bz : 1'b0; sound_i2c_rom sound_i2c_rom ( .clk (clk), .a (i2c_rom_a), .q (i2c_rom_q) ); // // We generate four types of symbols: "normal", where we assert SCL, // and "abnormal", where we don't. An S or Sr condition is composed of // A1 N0 and a P condition of A0 A1. A1 is the idle state. // always @(posedge clk) if ( ~rst_n ) begin // Synchronous reset // Note: we write register 15 (RESET) first, then 0-9. i2c_rom_a <= 4'd15; i2c_bit_ctr <= 5'd0; i2c_qtr <= 2'b00; i2c_active <= 1'b1; scl <= 1'b1; sda <= 1'b1; abn <= 1'b1; end else if ( clk_en & i2c_active & (~scl | i2c_scl) ) begin i2c_qtr <= i2c_qtr + 1; // Phase 1: set SCL to 1; phase 3: set SCL to abn if (i2c_qtr[0]) scl <= abn | ~i2c_qtr[1]; // Phase 0: load a new data bit, set up abn if (i2c_qtr == 2'b00) begin i2c_bit_ctr <= i2c_bit_ctr + 1; case ( i2c_bit_ctr ) // Start condition 5'd0: {abn, sda} <= 2'b11; // A1 5'd1: {abn, sda} <= 2'b00; // N0 // First byte (I2C address) 5'd2: {abn, sda} <= {1'b0, i2c_addr[6]}; 5'd3: {abn, sda} <= {1'b0, i2c_addr[5]}; 5'd4: {abn, sda} <= {1'b0, i2c_addr[4]}; 5'd5: {abn, sda} <= {1'b0, i2c_addr[3]}; 5'd6: {abn, sda} <= {1'b0, i2c_addr[2]}; 5'd7: {abn, sda} <= {1'b0, i2c_addr[1]}; 5'd8: {abn, sda} <= {1'b0, i2c_addr[0]}; 5'd9: {abn, sda} <= 2'b00; // Write 5'd10: {abn, sda} <= 2'b01; // ACK // Second byte (device register address + D8) 5'd11, 5'd12, 5'd13: {abn, sda} <= 2'b00; 5'd14: {abn, sda} <= {1'b0, i2c_rom_a[3]}; 5'd15: {abn, sda} <= {1'b0, i2c_rom_a[2]}; 5'd16: {abn, sda} <= {1'b0, i2c_rom_a[1]}; 5'd17: {abn, sda} <= {1'b0, i2c_rom_a[0]}; 5'd18: {abn, sda} <= {1'b0, i2c_rom_q[8]}; 5'd19: {abn, sda} <= 2'b01; // ACK // Third byte (D7-D0) 5'd20: {abn, sda} <= {1'b0, i2c_rom_q[7]}; 5'd21: {abn, sda} <= {1'b0, i2c_rom_q[6]}; 5'd22: {abn, sda} <= {1'b0, i2c_rom_q[5]}; 5'd23: {abn, sda} <= {1'b0, i2c_rom_q[4]}; 5'd24: {abn, sda} <= {1'b0, i2c_rom_q[3]}; 5'd25: {abn, sda} <= {1'b0, i2c_rom_q[2]}; 5'd26: {abn, sda} <= {1'b0, i2c_rom_q[1]}; 5'd27: {abn, sda} <= {1'b0, i2c_rom_q[0]}; 5'd28: {abn, sda} <= 2'b01; // ACK // Stop condition 5'd29: {abn, sda} <= 2'b10; // A0 5'd30: {abn, sda} <= 2'b11; // A1 // Idle cycle and prepare for the next loop 5'd31: begin {abn, sda} <= 2'b11; // A1 = idle i2c_rom_a <= i2c_rom_a + 1; i2c_active <= ~i2c_stop; end endcase // case( i2c_bit_ctr ) end // if (i2c_qtr == 2'b00) end // if ( clk_en & i2c_active & (~i2c_scl_out[3] | i2c_scl) ) endmodule // sound_i2c // Asynchronous ROM. If this is made larger, it should probably // be a synchronous ROM instead. module sound_i2c_rom ( input clk, input [3:0] a, output [8:0] q ); reg [8:0] q_reg; assign q = q_reg; // See the Wolfson WM8731 datasheet for the meaning of these values always @(*) case (a) 4'd15: q_reg <= 9'b000000000; // Device reset 4'd0: q_reg <= 9'b0_0_00_10111; // Left line in 4'd1: q_reg <= 9'b0_0_00_10111; // Right line in 4'd2: q_reg <= 9'b0_0_1111001; // Left headphone out 4'd3: q_reg <= 9'b0_0_1111001; // Right headphone out 4'd4: q_reg <= 9'b0_11_0_1_1_0_0_0; // Analogue audio path control 4'd5: q_reg <= 9'b0000_0_0_11_0; // Digital audio path control 4'd6: q_reg <= 9'b000000000; // Power down control 4'd7: q_reg <= 9'b0_0_0_0_0_00_10; // Digital audio interface format 4'd8: q_reg <= 9'b0_0_0_0111_0_0; // Sampling control 4'd9: q_reg <= 9'b00000000_1; // Active control (enable) default: q_reg <= 9'hxxx; endcase endmodule // sound_i2c_rom